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,431 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module Planner
6
+ # TypeChecker - Validates type compatibility and infers expression types
7
+ class TypeChecker
8
+ attr_reader :errors, :warnings
9
+
10
+ def initialize(catalog)
11
+ @catalog = catalog
12
+ @errors = []
13
+ @warnings = []
14
+ @current_scope = {}
15
+ @current_table = nil
16
+ end
17
+
18
+ # Type check a statement
19
+ def check(statement)
20
+ @errors = []
21
+ @warnings = []
22
+ statement.accept(self)
23
+ [statement, @errors, @warnings]
24
+ end
25
+
26
+ # --- Visitor methods ---
27
+
28
+ def visit_select(node)
29
+ # Build scope from FROM clause
30
+ if node.from
31
+ table_info = @catalog.find_table(node.from.name)
32
+ if table_info
33
+ @current_table = table_info
34
+ @current_scope = {}
35
+ table_info.columns.each do |col|
36
+ @current_scope[col.name] = col
37
+ end
38
+ end
39
+ end
40
+
41
+ # Check WHERE clause
42
+ if node.where
43
+ where_type = type_check_expression(node.where)
44
+ unless where_type == :boolean || where_type.nil?
45
+ @warnings << "WHERE clause should be boolean, got #{where_type}"
46
+ end
47
+ end
48
+
49
+ # Check columns
50
+ node.columns.each do |col|
51
+ if col.expression.is_a?(AST::Star)
52
+ # Star is always valid
53
+ next
54
+ end
55
+ type_check_expression(col.expression)
56
+ end
57
+
58
+ # Check ORDER BY
59
+ node.order_by.each do |order_item|
60
+ type_check_expression(order_item.expression)
61
+ end
62
+
63
+ # Check LIMIT and OFFSET
64
+ if node.limit
65
+ limit_type = type_check_expression(node.limit)
66
+ unless limit_type == :integer || limit_type.nil?
67
+ @warnings << "LIMIT should be integer, got #{limit_type}"
68
+ end
69
+ end
70
+
71
+ if node.offset
72
+ offset_type = type_check_expression(node.offset)
73
+ unless offset_type == :integer || offset_type.nil?
74
+ @warnings << "OFFSET should be integer, got #{offset_type}"
75
+ end
76
+ end
77
+
78
+ @current_scope = {}
79
+ @current_table = nil
80
+ end
81
+
82
+ def visit_insert(node)
83
+ table_info = @catalog.find_table(node.table)
84
+ if table_info
85
+ @current_table = table_info
86
+ @current_scope = {}
87
+ table_info.columns.each do |col|
88
+ @current_scope[col.name] = col
89
+ end
90
+ end
91
+
92
+ # Type check values
93
+ node.rows.each do |row|
94
+ row.each do |value|
95
+ type_check_expression(value)
96
+ end
97
+ end
98
+
99
+ @current_scope = {}
100
+ @current_table = nil
101
+ end
102
+
103
+ def visit_update(node)
104
+ table_info = @catalog.find_table(node.table)
105
+ if table_info
106
+ @current_table = table_info
107
+ @current_scope = {}
108
+ table_info.columns.each do |col|
109
+ @current_scope[col.name] = col
110
+ end
111
+ end
112
+
113
+ # Type check assignments
114
+ node.assignments.each do |assignment|
115
+ value_type = type_check_expression(assignment.value)
116
+
117
+ # Check if value type matches column type
118
+ if @current_scope.key?(assignment.column)
119
+ column = @current_scope[assignment.column]
120
+ col_type = column.type.to_sym
121
+ if value_type && !type_compatible?(value_type, col_type)
122
+ @warnings << "Type mismatch: column '#{assignment.column}' expects #{col_type}, got #{value_type}"
123
+ end
124
+ end
125
+ end
126
+
127
+ # Check WHERE clause
128
+ if node.where
129
+ where_type = type_check_expression(node.where)
130
+ unless where_type == :boolean || where_type.nil?
131
+ @warnings << "WHERE clause should be boolean, got #{where_type}"
132
+ end
133
+ end
134
+
135
+ @current_scope = {}
136
+ @current_table = nil
137
+ end
138
+
139
+ def visit_delete(node)
140
+ table_info = @catalog.find_table(node.table)
141
+ if table_info
142
+ @current_table = table_info
143
+ @current_scope = {}
144
+ table_info.columns.each do |col|
145
+ @current_scope[col.name] = col
146
+ end
147
+ end
148
+
149
+ # Check WHERE clause
150
+ if node.where
151
+ where_type = type_check_expression(node.where)
152
+ unless where_type == :boolean || where_type.nil?
153
+ @warnings << "WHERE clause should be boolean, got #{where_type}"
154
+ end
155
+ end
156
+
157
+ @current_scope = {}
158
+ @current_table = nil
159
+ end
160
+
161
+ def visit_create_table(node)
162
+ # Validate column types
163
+ node.columns.each do |col|
164
+ type_class = col.type_class
165
+ begin
166
+ Types::TypeRegistry.lookup(type_class)
167
+ rescue ConfigurationError
168
+ @errors << "Unknown data type '#{type_class}' for column '#{col.name}'"
169
+ end
170
+ end
171
+
172
+ # Validate constraints
173
+ node.constraints.each do |constraint|
174
+ constraint.accept(self)
175
+ end
176
+ end
177
+
178
+ # --- Expression type checking ---
179
+
180
+ def type_check_expression(expr)
181
+ case expr
182
+ when AST::BinaryOp
183
+ type_check_binary_op(expr)
184
+ when AST::UnaryOp
185
+ type_check_unary_op(expr)
186
+ when AST::Identifier
187
+ type_check_identifier(expr)
188
+ when AST::Literal
189
+ type_check_literal(expr)
190
+ when AST::Between
191
+ type_check_between(expr)
192
+ when AST::In
193
+ type_check_in(expr)
194
+ when AST::IsNull
195
+ type_check_is_null(expr)
196
+ when AST::FunctionCall
197
+ type_check_function_call(expr)
198
+ when AST::Parameter
199
+ # Parameters can be any type
200
+ nil
201
+ when AST::Star
202
+ # Star has no type
203
+ nil
204
+ else
205
+ nil
206
+ end
207
+ end
208
+
209
+ def type_check_binary_op(expr)
210
+ left_type = type_check_expression(expr.left)
211
+ right_type = type_check_expression(expr.right)
212
+
213
+ # Determine result type
214
+ case expr.operator
215
+ when Token::Type::EQ, Token::Type::NE,
216
+ Token::Type::LT, Token::Type::LTE,
217
+ Token::Type::GT, Token::Type::GTE,
218
+ Token::Type::LIKE, Token::Type::ILIKE,
219
+ Token::Type::IN
220
+ # Comparison operators return boolean
221
+ expr.type = :boolean
222
+ return :boolean
223
+
224
+ when Token::Type::AND, Token::Type::OR
225
+ # Logical operators require boolean operands
226
+ if left_type && left_type != :boolean
227
+ @warnings << "AND requires boolean left operand, got #{left_type}"
228
+ end
229
+ if right_type && right_type != :boolean
230
+ @warnings << "AND requires boolean right operand, got #{right_type}"
231
+ end
232
+ expr.type = :boolean
233
+ return :boolean
234
+
235
+ when Token::Type::PLUS, Token::Type::MINUS,
236
+ Token::Type::STAR, Token::Type::SLASH,
237
+ Token::Type::PERCENT
238
+ # Arithmetic operators require numeric operands
239
+ numeric_types = [:integer, :bigint, :smallint, :float, :decimal]
240
+ unless left_type.nil? || numeric_types.include?(left_type)
241
+ @warnings << "Arithmetic requires numeric left operand, got #{left_type}"
242
+ end
243
+ unless right_type.nil? || numeric_types.include?(right_type)
244
+ @warnings << "Arithmetic requires numeric right operand, got #{right_type}"
245
+ end
246
+
247
+ # Result type is numeric
248
+ result_type = left_type || right_type || :integer
249
+ expr.type = result_type
250
+ return result_type
251
+
252
+ else
253
+ expr.type = nil
254
+ return nil
255
+ end
256
+ end
257
+
258
+ def type_check_unary_op(expr)
259
+ operand_type = type_check_expression(expr.operand)
260
+
261
+ case expr.operator
262
+ when Token::Type::NOT
263
+ if operand_type && operand_type != :boolean
264
+ @warnings << "NOT requires boolean operand, got #{operand_type}"
265
+ end
266
+ expr.type = :boolean
267
+ return :boolean
268
+
269
+ when Token::Type::PLUS, Token::Type::MINUS, Token::Type::TILDE
270
+ numeric_types = [:integer, :bigint, :smallint, :float, :decimal]
271
+ unless operand_type.nil? || numeric_types.include?(operand_type)
272
+ @warnings << "Unary #{expr.operator} requires numeric operand, got #{operand_type}"
273
+ end
274
+ expr.type = operand_type || :integer
275
+ return expr.type
276
+
277
+ else
278
+ expr.type = nil
279
+ return nil
280
+ end
281
+ end
282
+
283
+ def type_check_identifier(expr)
284
+ # Look up column in current scope
285
+ if @current_scope.key?(expr.name)
286
+ column = @current_scope[expr.name]
287
+ expr.type = column.type.to_sym
288
+ return expr.type
289
+ end
290
+
291
+ # Not found
292
+ @errors << "Column '#{expr.name}' not found in current scope"
293
+ expr.type = nil
294
+ nil
295
+ end
296
+
297
+ def type_check_literal(expr)
298
+ case expr.token_type
299
+ when Token::Type::STRING
300
+ expr.type = :text
301
+ :text
302
+ when Token::Type::NUMBER
303
+ if expr.value.is_a?(Integer)
304
+ expr.type = :integer
305
+ :integer
306
+ else
307
+ expr.type = :float
308
+ :float
309
+ end
310
+ when Token::Type::TRUE, Token::Type::FALSE
311
+ expr.type = :boolean
312
+ :boolean
313
+ when Token::Type::NULL
314
+ expr.type = nil
315
+ nil
316
+ else
317
+ expr.type = nil
318
+ nil
319
+ end
320
+ end
321
+
322
+ def type_check_between(expr)
323
+ expr_type = type_check_expression(expr.expression)
324
+ low_type = type_check_expression(expr.low)
325
+ high_type = type_check_expression(expr.high)
326
+
327
+ # BETWEEN returns boolean
328
+ expr.type = :boolean
329
+ :boolean
330
+ end
331
+
332
+ def type_check_in(expr)
333
+ expr_type = type_check_expression(expr.expression)
334
+
335
+ # Check all values
336
+ expr.values.each do |value|
337
+ type_check_expression(value)
338
+ end
339
+
340
+ # IN returns boolean
341
+ expr.type = :boolean
342
+ :boolean
343
+ end
344
+
345
+ def type_check_is_null(expr)
346
+ type_check_expression(expr.expression)
347
+
348
+ # IS NULL returns boolean
349
+ expr.type = :boolean
350
+ :boolean
351
+ end
352
+
353
+ def type_check_function_call(expr)
354
+ # Check arguments
355
+ expr.arguments.each do |arg|
356
+ type_check_expression(arg)
357
+ end
358
+
359
+ # Determine function return type
360
+ return_type = function_return_type(expr.name)
361
+ expr.type = return_type
362
+ return_type
363
+ end
364
+
365
+ # --- Constraint type checking ---
366
+
367
+ def visit_primary_key_constraint(node)
368
+ # Validate columns exist (done in binder)
369
+ end
370
+
371
+ def visit_foreign_key_constraint(node)
372
+ # Validate columns exist (done in binder)
373
+ end
374
+
375
+ def visit_unique_constraint(node)
376
+ # Validate columns exist (done in binder)
377
+ end
378
+
379
+ def visit_check_constraint(node)
380
+ condition_type = type_check_expression(node.condition)
381
+ unless condition_type == :boolean || condition_type.nil?
382
+ @warnings << "CHECK constraint condition should be boolean, got #{condition_type}"
383
+ end
384
+ end
385
+
386
+ # --- Helper methods ---
387
+
388
+ private
389
+
390
+ def type_compatible?(type1, type2)
391
+ # Same type is always compatible
392
+ return true if type1 == type2
393
+
394
+ # Numeric types are compatible
395
+ numeric_types = [:integer, :bigint, :smallint, :float, :decimal]
396
+ if numeric_types.include?(type1) && numeric_types.include?(type2)
397
+ return true
398
+ end
399
+
400
+ # Text types are compatible
401
+ text_types = [:text, :varchar, :char]
402
+ if text_types.include?(type1) && text_types.include?(type2)
403
+ return true
404
+ end
405
+
406
+ false
407
+ end
408
+
409
+ def function_return_type(name)
410
+ # Define return types for common functions
411
+ case name.upcase
412
+ when "COUNT", "SUM", "AVG", "MAX", "MIN", "ROW_NUMBER", "RANK", "DENSE_RANK"
413
+ :integer
414
+ when "LOWER", "UPPER", "SUBSTR", "CONCAT", "COALESCE", "NULLIF"
415
+ :text
416
+ when "LENGTH"
417
+ :integer
418
+ when "DATE", "TIME", "TIMESTAMP"
419
+ :timestamp
420
+ when "EXTRACT"
421
+ :integer
422
+ when "JSON_ARRAY", "JSON_OBJECT", "JSON_EXTRACT"
423
+ :json
424
+ else
425
+ nil
426
+ end
427
+ end
428
+ end
429
+ end
430
+ end
431
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ # Token types for SQL lexer
6
+ class Token
7
+ # Token types
8
+ module Type
9
+ # Keywords
10
+ SELECT = :SELECT
11
+ INSERT = :INSERT
12
+ UPDATE = :UPDATE
13
+ DELETE = :DELETE
14
+ CREATE = :CREATE
15
+ ALTER = :ALTER
16
+ DROP = :DROP
17
+ TABLE = :TABLE
18
+ INDEX = :INDEX
19
+ DATABASE = :DATABASE
20
+ SCHEMA = :SCHEMA
21
+ VIEW = :VIEW
22
+ TRIGGER = :TRIGGER
23
+ FROM = :FROM
24
+ WHERE = :WHERE
25
+ SET = :SET
26
+ VALUES = :VALUES
27
+ INTO = :INTO
28
+ CONFLICT = :CONFLICT
29
+ DO = :DO
30
+ NOTHING = :NOTHING
31
+ JOIN = :JOIN
32
+ INNER = :INNER
33
+ LEFT = :LEFT
34
+ RIGHT = :RIGHT
35
+ OUTER = :OUTER
36
+ FULL = :FULL
37
+ CROSS = :CROSS
38
+ ON = :ON
39
+ AS = :AS
40
+ DISTINCT = :DISTINCT
41
+ ORDER = :ORDER
42
+ BY = :BY
43
+ ASC = :ASC
44
+ DESC = :DESC
45
+ GROUP = :GROUP
46
+ HAVING = :HAVING
47
+ LIMIT = :LIMIT
48
+ OFFSET = :OFFSET
49
+ UNION = :UNION
50
+ INTERSECT = :INTERSECT
51
+ EXCEPT = :EXCEPT
52
+ ALL = :ALL
53
+ ANY = :ANY
54
+ SOME = :SOME
55
+ EXISTS = :EXISTS
56
+ IF = :IF
57
+ BETWEEN = :BETWEEN
58
+ LIKE = :LIKE
59
+ ILIKE = :ILIKE
60
+ IN = :IN
61
+ IS = :IS
62
+ NULL = :NULL
63
+ NOT = :NOT
64
+ AND = :AND
65
+ OR = :OR
66
+ TRUE = :TRUE
67
+ FALSE = :FALSE
68
+ PRIMARY = :PRIMARY
69
+ FOREIGN = :FOREIGN
70
+ KEY = :KEY
71
+ UNIQUE = :UNIQUE
72
+ CHECK = :CHECK
73
+ DEFAULT = :DEFAULT
74
+ REFERENCES = :REFERENCES
75
+ CONSTRAINT = :CONSTRAINT
76
+ CASCADE = :CASCADE
77
+ RESTRICT = :RESTRICT
78
+ ADD = :ADD
79
+ TO = :TO
80
+ BEFORE = :BEFORE
81
+ AFTER = :AFTER
82
+ EXECUTE = :EXECUTE
83
+ FUNCTION = :FUNCTION
84
+ BEGIN_TRANSACTION = :BEGIN
85
+ COMMIT = :COMMIT
86
+ ROLLBACK = :ROLLBACK
87
+ SAVEPOINT = :SAVEPOINT
88
+ RELEASE = :RELEASE
89
+ TRANSACTION = :TRANSACTION
90
+ EXPLAIN = :EXPLAIN
91
+ ANALYZE = :ANALYZE
92
+ VACUUM = :VACUUM
93
+ WITH = :WITH
94
+ RECURSIVE = :RECURSIVE
95
+ OVER = :OVER
96
+ PARTITION = :PARTITION
97
+ ROWS = :ROWS
98
+ UNBOUNDED = :UNBOUNDED
99
+ PRECEDING = :PRECEDING
100
+ FOLLOWING = :FOLLOWING
101
+ CURRENT = :CURRENT
102
+
103
+ # Data types
104
+ INTEGER = :INTEGER
105
+ BIGINT = :BIGINT
106
+ SMALLINT = :SMALLINT
107
+ FLOAT = :FLOAT
108
+ DECIMAL = :DECIMAL
109
+ NUMERIC = :NUMERIC
110
+ BOOLEAN = :BOOLEAN
111
+ TEXT = :TEXT
112
+ VARCHAR = :VARCHAR
113
+ CHAR = :CHAR
114
+ BLOB = :BLOB
115
+ DATE = :DATE
116
+ TIME = :TIME
117
+ TIMESTAMP = :TIMESTAMP
118
+ JSON = :JSON
119
+ UUID = :UUID
120
+
121
+ # Operators
122
+ EQ = :EQ # =
123
+ NE = :NE # != or <>
124
+ LT = :LT # <
125
+ LTE = :LTE # <=
126
+ GT = :GT # >
127
+ GTE = :GTE # >=
128
+ PLUS = :PLUS # +
129
+ MINUS = :MINUS # -
130
+ STAR = :STAR # *
131
+ SLASH = :SLASH # /
132
+ PERCENT = :PERCENT # %
133
+ AMPERSAND = :AMPERSAND # &
134
+ PIPE = :PIPE # |
135
+ CARET = :CARET # ^
136
+ TILDE = :TILDE # ~
137
+
138
+ # Punctuation
139
+ LPAREN = :LPAREN # (
140
+ RPAREN = :RPAREN # )
141
+ COMMA = :COMMA # ,
142
+ SEMICOLON = :SEMICOLON # ;
143
+ DOT = :DOT # .
144
+ LBRACKET = :LBRACKET # [
145
+ RBRACKET = :RBRACKET # ]
146
+ LBRACE = :LBRACE # {
147
+ RBRACE = :RBRACE # }
148
+
149
+ # Literals
150
+ IDENTIFIER = :IDENTIFIER
151
+ STRING = :STRING
152
+ NUMBER = :NUMBER
153
+ BLOB_LITERAL = :BLOB_LITERAL
154
+
155
+ # Special
156
+ EOF = :EOF
157
+ COMMENT = :COMMENT
158
+ PARAMETER = :PARAMETER # ? or $1, $2, etc.
159
+ end
160
+
161
+ attr_reader :type, :value, :line, :column
162
+
163
+ def initialize(type, value = nil, line: 1, column: 1)
164
+ @type = type
165
+ @value = value
166
+ @line = line
167
+ @column = column
168
+ end
169
+
170
+ def keyword?
171
+ @type.to_s.start_with?("KEYWORD_") || false
172
+ end
173
+
174
+ def operator?
175
+ [
176
+ Type::EQ, Type::NE, Type::LT, Type::LTE,
177
+ Type::GT, Type::GTE, Type::PLUS, Type::MINUS,
178
+ Type::STAR, Type::SLASH, Type::PERCENT,
179
+ Type::AMPERSAND, Type::PIPE, Type::CARET, Type::TILDE
180
+ ].include?(@type)
181
+ end
182
+
183
+ def literal?
184
+ [Type::STRING, Type::NUMBER, Type::BLOB_LITERAL].include?(@type)
185
+ end
186
+
187
+ def identifier?
188
+ @type == Type::IDENTIFIER
189
+ end
190
+
191
+ def to_s
192
+ if @value
193
+ "#{@type}(#{@value})"
194
+ else
195
+ @type.to_s
196
+ end
197
+ end
198
+
199
+ def inspect
200
+ to_s
201
+ end
202
+
203
+ # Equality check for testing
204
+ def ==(other)
205
+ return false unless other.is_a?(Token)
206
+ @type == other.type && @value == other.value
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Storage
5
+ # BufferFrame - Holds a page in the buffer pool
6
+ class BufferFrame
7
+ attr_accessor :page, :dirty, :pinned, :access_count
8
+
9
+ def initialize(page)
10
+ @page = page
11
+ @dirty = false
12
+ @pinned = 0
13
+ @access_count = 0
14
+ @created_at = Time.now
15
+ @last_access = Time.now
16
+ end
17
+
18
+ def pin
19
+ @pinned += 1
20
+ end
21
+
22
+ def unpin
23
+ @pinned -= 1 if @pinned > 0
24
+ end
25
+
26
+ def pinned?
27
+ @pinned > 0
28
+ end
29
+
30
+ def access
31
+ @access_count += 1
32
+ @last_access = Time.now
33
+ end
34
+
35
+ def to_s
36
+ "BufferFrame(page=#{@page.page_number}, dirty=#{@dirty}, pinned=#{@pinned}, accesses=#{@access_count})"
37
+ end
38
+
39
+ def inspect
40
+ to_s
41
+ end
42
+ end
43
+ end
44
+ end