lora-python 0.8.0__tar.gz → 0.8.1__tar.gz

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 (251) hide show
  1. {lora_python-0.8.0 → lora_python-0.8.1}/Cargo.lock +16 -16
  2. {lora_python-0.8.0 → lora_python-0.8.1}/Cargo.toml +11 -11
  3. {lora_python-0.8.0 → lora_python-0.8.1}/PKG-INFO +1 -1
  4. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/builder.rs +4 -4
  5. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/mod.rs +25 -24
  6. lora_python-0.8.1/crates/lora-database/src/database/occ.rs +137 -0
  7. lora_python-0.8.1/crates/lora-database/src/database/replay.rs +144 -0
  8. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/lib.rs +1 -0
  9. lora_python-0.8.1/crates/lora-database/src/live_store.rs +92 -0
  10. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/stream.rs +3 -4
  11. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/transaction.rs +3 -4
  12. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/transactions.rs +13 -13
  13. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/wal.rs +29 -18
  14. {lora_python-0.8.0 → lora_python-0.8.1}/pyproject.toml +1 -1
  15. lora_python-0.8.0/crates/lora-database/src/database/occ.rs +0 -184
  16. lora_python-0.8.0/crates/lora-database/src/database/replay.rs +0 -303
  17. {lora_python-0.8.0 → lora_python-0.8.1}/LICENSE +0 -0
  18. {lora_python-0.8.0 → lora_python-0.8.1}/README.md +0 -0
  19. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/.gitignore +0 -0
  20. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/Cargo.toml +0 -0
  21. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/LICENSE +0 -0
  22. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/README.md +0 -0
  23. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/build.rs +0 -0
  24. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/examples/async_demo.py +0 -0
  25. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/examples/basic.py +0 -0
  26. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/src/errors.rs +0 -0
  27. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/src/from_python.rs +0 -0
  28. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/src/lib.rs +0 -0
  29. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/src/to_python.rs +0 -0
  30. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/tests/test_async.py +0 -0
  31. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/tests/test_explain_profile.py +0 -0
  32. {lora_python-0.8.0 → lora_python-0.8.1}/crates/bindings/lora-python/tests/test_sync.py +0 -0
  33. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/Cargo.toml +0 -0
  34. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/clauses.rs +0 -0
  35. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/expressions.rs +0 -0
  36. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/mod.rs +0 -0
  37. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/patterns.rs +0 -0
  38. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/state.rs +0 -0
  39. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/analyzer/tests.rs +0 -0
  40. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/errors.rs +0 -0
  41. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/lib.rs +0 -0
  42. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/resolved.rs +0 -0
  43. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/scope.rs +0 -0
  44. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/src/symbols.rs +0 -0
  45. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-analyzer/tests/error_messages.rs +0 -0
  46. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-ast/Cargo.toml +0 -0
  47. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-ast/src/ast.rs +0 -0
  48. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-ast/src/lib.rs +0 -0
  49. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/Cargo.toml +0 -0
  50. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/lib.rs +0 -0
  51. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/logical.rs +0 -0
  52. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/optimizer.rs +0 -0
  53. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/pattern.rs +0 -0
  54. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/physical.rs +0 -0
  55. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/plan_tree.rs +0 -0
  56. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-compiler/src/planner.rs +0 -0
  57. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/Cargo.toml +0 -0
  58. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/advanced_benchmarks.rs +0 -0
  59. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/concurrent_benchmarks.rs +0 -0
  60. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/engine_benchmarks.rs +0 -0
  61. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/fixtures.rs +0 -0
  62. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/perf_smoke_baseline.json +0 -0
  63. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/perf_smoke_benchmarks.rs +0 -0
  64. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/scale_benchmarks.rs +0 -0
  65. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/temporal_spatial_benchmarks.rs +0 -0
  66. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/benches/wal_benchmarks.rs +0 -0
  67. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/compile.rs +0 -0
  68. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/execute.rs +0 -0
  69. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/explain.rs +0 -0
  70. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/graph_api.rs +0 -0
  71. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/profile.rs +0 -0
  72. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/pull_mode.rs +0 -0
  73. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/stream.rs +0 -0
  74. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/database/write_guard.rs +0 -0
  75. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/error.rs +0 -0
  76. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/explain.rs +0 -0
  77. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/named.rs +0 -0
  78. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/plan_cache.rs +0 -0
  79. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/snapshot/json.rs +0 -0
  80. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/snapshot/mod.rs +0 -0
  81. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/snapshot/store.rs +0 -0
  82. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/admin.rs +0 -0
  83. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive/format.rs +0 -0
  84. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive/lock.rs +0 -0
  85. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive/platform.rs +0 -0
  86. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive/worker.rs +0 -0
  87. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive/workspace.rs +0 -0
  88. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/archive.rs +0 -0
  89. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/mod.rs +0 -0
  90. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/src/wal/write_scope.rs +0 -0
  91. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/advanced_queries.rs +0 -0
  92. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/aggregation.rs +0 -0
  93. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/backend_stub.rs +0 -0
  94. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/binary.rs +0 -0
  95. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/create.rs +0 -0
  96. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/error_messages.rs +0 -0
  97. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/errors.rs +0 -0
  98. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/explain_profile.rs +0 -0
  99. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/expressions.rs +0 -0
  100. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/functions_extended.rs +0 -0
  101. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/invariants.rs +0 -0
  102. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/managed_snapshots.rs +0 -0
  103. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/match.rs +0 -0
  104. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/merge.rs +0 -0
  105. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/ordering.rs +0 -0
  106. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/parameters.rs +0 -0
  107. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/parser.rs +0 -0
  108. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/paths.rs +0 -0
  109. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/projection.rs +0 -0
  110. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/scale.rs +0 -0
  111. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/seeds.rs +0 -0
  112. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/snapshot.rs +0 -0
  113. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/spatial.rs +0 -0
  114. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/temporal.rs +0 -0
  115. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/test_helpers.rs +0 -0
  116. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/types_advanced.rs +0 -0
  117. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/union.rs +0 -0
  118. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/update.rs +0 -0
  119. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/vectors.rs +0 -0
  120. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/where_clause.rs +0 -0
  121. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-database/tests/with.rs +0 -0
  122. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/Cargo.toml +0 -0
  123. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/errors.rs +0 -0
  124. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/binops.rs +0 -0
  125. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/errors.rs +0 -0
  126. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/expr.rs +0 -0
  127. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/functions.rs +0 -0
  128. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/mod.rs +0 -0
  129. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/point.rs +0 -0
  130. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/eval/vector.rs +0 -0
  131. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/executor/helpers.rs +0 -0
  132. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/executor/immutable.rs +0 -0
  133. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/executor/mod.rs +0 -0
  134. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/executor/mutable.rs +0 -0
  135. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/lib.rs +0 -0
  136. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/profile.rs +0 -0
  137. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/aggregate.rs +0 -0
  138. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/columns.rs +0 -0
  139. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/context.rs +0 -0
  140. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/expand.rs +0 -0
  141. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/filter.rs +0 -0
  142. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/hydration.rs +0 -0
  143. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/mod.rs +0 -0
  144. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/mutable.rs +0 -0
  145. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/optional.rs +0 -0
  146. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/path.rs +0 -0
  147. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/projection.rs +0 -0
  148. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/scan.rs +0 -0
  149. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/shape.rs +0 -0
  150. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/sort.rs +0 -0
  151. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/source.rs +0 -0
  152. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/tests.rs +0 -0
  153. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/traits.rs +0 -0
  154. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/pull/union.rs +0 -0
  155. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/src/value.rs +0 -0
  156. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-executor/tests/error_messages.rs +0 -0
  157. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/Cargo.toml +0 -0
  158. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/cypher.pest +0 -0
  159. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/errors.rs +0 -0
  160. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/lib.rs +0 -0
  161. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/clauses.rs +0 -0
  162. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/expressions.rs +0 -0
  163. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/literals.rs +0 -0
  164. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/mod.rs +0 -0
  165. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/patterns.rs +0 -0
  166. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/query.rs +0 -0
  167. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/tests.rs +0 -0
  168. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/src/parser/util.rs +0 -0
  169. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-parser/tests/error_messages.rs +0 -0
  170. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/Cargo.toml +0 -0
  171. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/body.rs +0 -0
  172. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/codec.rs +0 -0
  173. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/columnar.rs +0 -0
  174. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/envelope.rs +0 -0
  175. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/errors.rs +0 -0
  176. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/format.rs +0 -0
  177. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/lib.rs +0 -0
  178. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/options.rs +0 -0
  179. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/tests.rs +0 -0
  180. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/transform.rs +0 -0
  181. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/src/view.rs +0 -0
  182. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-snapshot/tests/error_messages.rs +0 -0
  183. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/Cargo.toml +0 -0
  184. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/lib.rs +0 -0
  185. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/lock_table.rs +0 -0
  186. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/graph.rs +0 -0
  187. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/impls.rs +0 -0
  188. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/mod.rs +0 -0
  189. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/property_index.rs +0 -0
  190. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/snapshot.rs +0 -0
  191. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/memory/tests.rs +0 -0
  192. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/mutation.rs +0 -0
  193. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/snapshot.rs +0 -0
  194. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/traits.rs +0 -0
  195. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/binary/mod.rs +0 -0
  196. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/binary/tests.rs +0 -0
  197. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/binary/traits.rs +0 -0
  198. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/binary/types.rs +0 -0
  199. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/graph.rs +0 -0
  200. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/mod.rs +0 -0
  201. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/property_value.rs +0 -0
  202. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/spatial/distance.rs +0 -0
  203. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/spatial/mod.rs +0 -0
  204. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/spatial/point.rs +0 -0
  205. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/spatial/srid.rs +0 -0
  206. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/spatial/tests.rs +0 -0
  207. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/calendar.rs +0 -0
  208. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/date.rs +0 -0
  209. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/datetime.rs +0 -0
  210. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/duration.rs +0 -0
  211. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/format.rs +0 -0
  212. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/mod.rs +0 -0
  213. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/parsing.rs +0 -0
  214. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/temporal/time.rs +0 -0
  215. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/vector/build.rs +0 -0
  216. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/vector/mod.rs +0 -0
  217. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/vector/similarity.rs +0 -0
  218. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/vector/tests.rs +0 -0
  219. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/src/types/vector/types.rs +0 -0
  220. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-store/tests/error_messages.rs +0 -0
  221. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/Cargo.toml +0 -0
  222. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/codec/decode.rs +0 -0
  223. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/codec/encode.rs +0 -0
  224. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/codec/format.rs +0 -0
  225. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/codec/mod.rs +0 -0
  226. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/codec/tests.rs +0 -0
  227. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/config.rs +0 -0
  228. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/dir.rs +0 -0
  229. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/errors.rs +0 -0
  230. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/lib.rs +0 -0
  231. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/lock.rs +0 -0
  232. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/lsn.rs +0 -0
  233. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/record.rs +0 -0
  234. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/recorder/errors.rs +0 -0
  235. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/recorder/mirror.rs +0 -0
  236. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/recorder/mod.rs +0 -0
  237. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/recorder/recorder.rs +0 -0
  238. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/recorder/tests.rs +0 -0
  239. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/replay.rs +0 -0
  240. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/segment.rs +0 -0
  241. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/testing.rs +0 -0
  242. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/wal/group_flusher.rs +0 -0
  243. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/wal/mod.rs +0 -0
  244. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/wal/tests.rs +0 -0
  245. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/src/wal/wal.rs +0 -0
  246. {lora_python-0.8.0 → lora_python-0.8.1}/crates/lora-wal/tests/error_messages.rs +0 -0
  247. {lora_python-0.8.0 → lora_python-0.8.1}/python/lora_python/__init__.py +0 -0
  248. {lora_python-0.8.0 → lora_python-0.8.1}/python/lora_python/_async.py +0 -0
  249. {lora_python-0.8.0 → lora_python-0.8.1}/python/lora_python/_native.pyi +0 -0
  250. {lora_python-0.8.0 → lora_python-0.8.1}/python/lora_python/py.typed +0 -0
  251. {lora_python-0.8.0 → lora_python-0.8.1}/python/lora_python/types.py +0 -0
@@ -797,7 +797,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
797
797
 
798
798
  [[package]]
799
799
  name = "lora-analyzer"
800
- version = "0.8.0"
800
+ version = "0.8.1"
801
801
  dependencies = [
802
802
  "lora-ast",
803
803
  "lora-parser",
@@ -807,14 +807,14 @@ dependencies = [
807
807
 
808
808
  [[package]]
809
809
  name = "lora-ast"
810
- version = "0.8.0"
810
+ version = "0.8.1"
811
811
  dependencies = [
812
812
  "smallvec 2.0.0-alpha.12",
813
813
  ]
814
814
 
815
815
  [[package]]
816
816
  name = "lora-binding-buffer"
817
- version = "0.8.0"
817
+ version = "0.8.1"
818
818
  dependencies = [
819
819
  "lora-database",
820
820
  "lora-store",
@@ -822,7 +822,7 @@ dependencies = [
822
822
 
823
823
  [[package]]
824
824
  name = "lora-compiler"
825
- version = "0.8.0"
825
+ version = "0.8.1"
826
826
  dependencies = [
827
827
  "lora-analyzer",
828
828
  "lora-ast",
@@ -830,7 +830,7 @@ dependencies = [
830
830
 
831
831
  [[package]]
832
832
  name = "lora-database"
833
- version = "0.8.0"
833
+ version = "0.8.1"
834
834
  dependencies = [
835
835
  "anyhow",
836
836
  "arc-swap",
@@ -852,7 +852,7 @@ dependencies = [
852
852
 
853
853
  [[package]]
854
854
  name = "lora-executor"
855
- version = "0.8.0"
855
+ version = "0.8.1"
856
856
  dependencies = [
857
857
  "lora-analyzer",
858
858
  "lora-ast",
@@ -867,7 +867,7 @@ dependencies = [
867
867
 
868
868
  [[package]]
869
869
  name = "lora-ffi"
870
- version = "0.8.0"
870
+ version = "0.8.1"
871
871
  dependencies = [
872
872
  "anyhow",
873
873
  "lora-binding-buffer",
@@ -879,7 +879,7 @@ dependencies = [
879
879
 
880
880
  [[package]]
881
881
  name = "lora-node"
882
- version = "0.8.0"
882
+ version = "0.8.1"
883
883
  dependencies = [
884
884
  "anyhow",
885
885
  "lora-binding-buffer",
@@ -894,7 +894,7 @@ dependencies = [
894
894
 
895
895
  [[package]]
896
896
  name = "lora-parser"
897
- version = "0.8.0"
897
+ version = "0.8.1"
898
898
  dependencies = [
899
899
  "lora-ast",
900
900
  "pest",
@@ -905,7 +905,7 @@ dependencies = [
905
905
 
906
906
  [[package]]
907
907
  name = "lora-python"
908
- version = "0.8.0"
908
+ version = "0.8.1"
909
909
  dependencies = [
910
910
  "anyhow",
911
911
  "lora-database",
@@ -917,7 +917,7 @@ dependencies = [
917
917
 
918
918
  [[package]]
919
919
  name = "lora-server"
920
- version = "0.8.0"
920
+ version = "0.8.1"
921
921
  dependencies = [
922
922
  "anyhow",
923
923
  "axum",
@@ -931,7 +931,7 @@ dependencies = [
931
931
 
932
932
  [[package]]
933
933
  name = "lora-snapshot"
934
- version = "0.8.0"
934
+ version = "0.8.1"
935
935
  dependencies = [
936
936
  "argon2",
937
937
  "bincode",
@@ -946,7 +946,7 @@ dependencies = [
946
946
 
947
947
  [[package]]
948
948
  name = "lora-store"
949
- version = "0.8.0"
949
+ version = "0.8.1"
950
950
  dependencies = [
951
951
  "bincode",
952
952
  "crc32fast",
@@ -958,7 +958,7 @@ dependencies = [
958
958
 
959
959
  [[package]]
960
960
  name = "lora-wal"
961
- version = "0.8.0"
961
+ version = "0.8.1"
962
962
  dependencies = [
963
963
  "crc32fast",
964
964
  "lora-store",
@@ -968,7 +968,7 @@ dependencies = [
968
968
 
969
969
  [[package]]
970
970
  name = "lora-wasm"
971
- version = "0.8.0"
971
+ version = "0.8.1"
972
972
  dependencies = [
973
973
  "anyhow",
974
974
  "console_error_panic_hook",
@@ -984,7 +984,7 @@ dependencies = [
984
984
 
985
985
  [[package]]
986
986
  name = "lora_ruby"
987
- version = "0.8.0"
987
+ version = "0.8.1"
988
988
  dependencies = [
989
989
  "anyhow",
990
990
  "lora-database",
@@ -4,7 +4,7 @@ resolver = "2"
4
4
 
5
5
  [workspace.package]
6
6
  edition = "2021"
7
- version = "0.8.0"
7
+ version = "0.8.1"
8
8
  license = "BUSL-1.1"
9
9
  authors = ["LoraDB, Inc."]
10
10
  repository = "https://github.com/lora-db/lora"
@@ -15,16 +15,16 @@ rust-version = "1.87"
15
15
  # Internal crates — versions are kept in lockstep with [workspace.package].version
16
16
  # by `scripts/sync-versions.mjs`. Both `path` and `version` are set so that
17
17
  # `cargo publish` works (crates.io cannot resolve path-only deps).
18
- lora-ast = { path = "crates/lora-ast", version = "=0.8.0" }
19
- lora-parser = { path = "crates/lora-parser", version = "=0.8.0" }
20
- lora-analyzer = { path = "crates/lora-analyzer", version = "=0.8.0" }
21
- lora-compiler = { path = "crates/lora-compiler", version = "=0.8.0" }
22
- lora-store = { path = "crates/lora-store", version = "=0.8.0" }
23
- lora-snapshot = { path = "crates/lora-snapshot", version = "=0.8.0", default-features = false }
24
- lora-wal = { path = "crates/lora-wal", version = "=0.8.0" }
25
- lora-executor = { path = "crates/lora-executor", version = "=0.8.0" }
26
- lora-database = { path = "crates/lora-database", version = "=0.8.0" }
27
- lora-binding-buffer = { path = "crates/bindings/lora-binding-buffer", version = "=0.8.0" }
18
+ lora-ast = { path = "crates/lora-ast", version = "=0.8.1" }
19
+ lora-parser = { path = "crates/lora-parser", version = "=0.8.1" }
20
+ lora-analyzer = { path = "crates/lora-analyzer", version = "=0.8.1" }
21
+ lora-compiler = { path = "crates/lora-compiler", version = "=0.8.1" }
22
+ lora-store = { path = "crates/lora-store", version = "=0.8.1" }
23
+ lora-snapshot = { path = "crates/lora-snapshot", version = "=0.8.1", default-features = false }
24
+ lora-wal = { path = "crates/lora-wal", version = "=0.8.1" }
25
+ lora-executor = { path = "crates/lora-executor", version = "=0.8.1" }
26
+ lora-database = { path = "crates/lora-database", version = "=0.8.1" }
27
+ lora-binding-buffer = { path = "crates/bindings/lora-binding-buffer", version = "=0.8.1" }
28
28
 
29
29
  # External crates.
30
30
  anyhow = "1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lora-python
3
- Version: 0.8.0
3
+ Version: 0.8.1
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -21,12 +21,12 @@ use std::io::BufReader;
21
21
  use std::path::Path;
22
22
  use std::sync::{Arc, Mutex};
23
23
 
24
- use arc_swap::ArcSwap;
25
24
  use lora_store::{GraphStorage, GraphStorageMut, InMemoryGraph, MutationRecorder};
26
25
  use lora_wal::{replay_dir, Lsn, Wal, WalConfig, WalMirror, WalRecorder};
27
26
 
28
27
  use crate::database::Database;
29
28
  use crate::error::{LoraError, LoraErrorCode};
29
+ use crate::live_store::LiveStore;
30
30
  use crate::named::{DatabaseName, DatabaseOpenOptions};
31
31
  use crate::plan_cache::PlanCache;
32
32
  use crate::snapshot::{ManagedSnapshotStore, SnapshotConfig};
@@ -221,7 +221,7 @@ impl Database<InMemoryGraph> {
221
221
  ) -> Self {
222
222
  graph.set_mutation_recorder(Some(recorder.clone() as Arc<dyn MutationRecorder>));
223
223
  Self {
224
- store: Arc::new(ArcSwap::from(Arc::new(graph))),
224
+ store: Arc::new(LiveStore::new(Arc::new(graph))),
225
225
  writer: Arc::new(Mutex::new(())),
226
226
  lock_table: Arc::new(lora_store::LockTable::new()),
227
227
  wal: Some(recorder),
@@ -236,7 +236,7 @@ where
236
236
  S: GraphStorage + GraphStorageMut + Any + Clone + Send + Sync + 'static,
237
237
  {
238
238
  /// Build a database from a pre-wrapped, shared store.
239
- pub fn new(store: Arc<ArcSwap<S>>) -> Self {
239
+ pub(crate) fn new(store: Arc<LiveStore<S>>) -> Self {
240
240
  Self {
241
241
  store,
242
242
  writer: Arc::new(Mutex::new(())),
@@ -249,6 +249,6 @@ where
249
249
 
250
250
  /// Build a database by taking ownership of a bare graph store.
251
251
  pub fn from_graph(graph: S) -> Self {
252
- Self::new(Arc::new(ArcSwap::from(Arc::new(graph))))
252
+ Self::new(Arc::new(LiveStore::new(Arc::new(graph))))
253
253
  }
254
254
  }
@@ -2,8 +2,6 @@ use std::any::Any;
2
2
  use std::collections::BTreeMap;
3
3
  use std::sync::{Arc, Mutex};
4
4
 
5
- use arc_swap::ArcSwap;
6
-
7
5
  use anyhow::{anyhow, Result};
8
6
  use lora_ast::{Direction, Document};
9
7
  use lora_executor::{lora_value_to_property, ExecuteOptions, LoraValue, QueryResult};
@@ -25,6 +23,7 @@ mod write_guard;
25
23
 
26
24
  use crate::error::LoraError;
27
25
  use crate::explain::{QueryPlan, QueryProfile};
26
+ use crate::live_store::LiveStore;
28
27
  use crate::plan_cache::PlanCache;
29
28
  use crate::snapshot::ManagedSnapshotStore;
30
29
  use crate::wal::write_scope::WalAbortPolicy;
@@ -72,25 +71,25 @@ pub trait QueryRunner: Send + Sync + 'static {
72
71
  /// the WAL handle is `None` and the engine pays only the existing
73
72
  /// `MutationRecorder::record` null-pointer check per mutation.
74
73
  pub struct Database<S> {
75
- /// The current authoritative store, atomically swappable. Reads call
76
- /// `store.load_full()` to obtain an `Arc<S>` snapshot no lock, no
77
- /// blocking and run their executor against `&*snapshot`. Writes
78
- /// take the `writer` Mutex (for commit-order serialization), clone
79
- /// the current snapshot into a working copy, mutate that copy, append
80
- /// to the WAL, then `store.store(Arc::new(staged))` to publish.
81
- /// Concurrent reads keep their old `Arc<S>` alive until they drop it,
82
- /// which gives natural snapshot isolation.
83
- pub(crate) store: Arc<ArcSwap<S>>,
84
- /// Serializes commit ordering. Held only across `clone-mutate-WAL-publish`,
85
- /// not around any read. Multiple readers proceed concurrently with a
86
- /// writer; only writers contend with each other on this Mutex.
74
+ /// The current authoritative store. Reads call `store.load_full()`
75
+ /// to obtain an independent `Arc<S>` snapshot; writers take the
76
+ /// `writer` Mutex and then a brief write-lock on the inner
77
+ /// `RwLock<Arc<S>>`, mutating in-place via `Arc::make_mut`. When
78
+ /// no in-flight reader holds a snapshot Arc, `make_mut` returns
79
+ /// `&mut S` without cloning the graph that's the single-writer
80
+ /// fast path that "CREATE one node" / "SET property" depend on
81
+ /// for graph-size-independent throughput. When concurrent readers
82
+ /// are alive, `make_mut` clones once and the readers keep
83
+ /// observing the pre-mutation state via their old Arc.
84
+ pub(crate) store: Arc<LiveStore<S>>,
85
+ /// Serializes commit ordering. Held across `mutate-WAL-publish` so
86
+ /// WAL records are appended in the same order live state advances.
87
+ /// Readers never touch this Mutex; only writers contend.
87
88
  pub(crate) writer: Arc<Mutex<()>>,
88
- /// Per-record write locks, plumbed in Phase 4.1. Phase 4.2 keeps
89
- /// the writer Mutex serialization model so the lock table sits
90
- /// idle for now; it becomes load-bearing in a future phase that
91
- /// drops the writer Mutex in favour of ArcSwap CAS for true
92
- /// concurrent commits, where two writers with overlapping write
93
- /// sets need a real serialization point.
89
+ /// Per-record write locks. Plumbed for a future phase that allows
90
+ /// concurrent commits across disjoint write sets; today the writer
91
+ /// Mutex provides single-writer-at-a-time semantics so this table
92
+ /// is idle.
94
93
  #[allow(dead_code)]
95
94
  pub(crate) lock_table: Arc<lora_store::LockTable>,
96
95
  pub(crate) wal: Option<Arc<WalRecorder>>,
@@ -159,10 +158,12 @@ where
159
158
  self.wal.as_ref()
160
159
  }
161
160
 
162
- /// Handle to the underlying shared store useful for callers that need
163
- /// to snapshot or share the graph across multiple databases.
164
- pub fn store(&self) -> &Arc<ArcSwap<S>> {
165
- &self.store
161
+ /// Snapshot the current authoritative graph. Equivalent to the
162
+ /// historical `database.store().load_full()` pattern, exposed here
163
+ /// so external callers don't need to name the internal storage
164
+ /// wrapper.
165
+ pub fn snapshot(&self) -> Arc<S> {
166
+ self.store.load_full()
166
167
  }
167
168
 
168
169
  /// Parse a query string into an AST without executing it.
@@ -0,0 +1,137 @@
1
+ //! Single-writer auto-commit write path for `InMemoryGraph`.
2
+ //!
3
+ //! Earlier revisions cloned the entire snapshot into a "staged" graph
4
+ //! per mutating query (see `git log` for the OCC + `ArcSwap` design).
5
+ //! That made every CREATE / SET / DELETE pay an O(N+E) graph clone,
6
+ //! which dominated wall-clock for write-heavy benches against large
7
+ //! graphs.
8
+ //!
9
+ //! The current implementation acquires the writer mutex, takes the
10
+ //! `RwLock` write guard inside [`LiveStore`], and uses
11
+ //! `Arc::make_mut` against the live `Arc<S>`. When no in-flight reader
12
+ //! holds a snapshot Arc clone, `make_mut` returns `&mut S` *without*
13
+ //! cloning the graph — restoring v0.6's mutate-in-place cost.
14
+ //! Concurrent readers, when present, force a single CoW clone and keep
15
+ //! observing their pre-mutation snapshot via the Arc they already
16
+ //! hold.
17
+ //!
18
+ //! Trade-off vs. the prior OCC clone-then-publish: a query that
19
+ //! fails mid-execution leaves the live graph partially mutated. The
20
+ //! WAL records are not appended (the buffer is drained without
21
+ //! commit), so durable state stays consistent and recovery from
22
+ //! snapshot+WAL is unaffected. The same caveat applies to the
23
+ //! pessimistic `with_logged_write_guard` path with
24
+ //! `WalAbortPolicy::PoisonIfMutated`.
25
+
26
+ use std::any::Any;
27
+ use std::collections::BTreeMap;
28
+ use std::sync::{Arc, Mutex};
29
+ use std::time::Instant;
30
+
31
+ use anyhow::Result;
32
+ use lora_compiler::CompiledQuery;
33
+ use lora_executor::{LoraValue, MutableExecutionContext, MutableExecutor, Row};
34
+ use lora_store::{GraphStorage, GraphStorageMut, MutationEvent, MutationRecorder};
35
+
36
+ use crate::database::Database;
37
+ use crate::transaction::BufferingRecorder;
38
+ use crate::wal::write_scope::ensure_wal_query_can_start;
39
+
40
+ use super::replay::install_recorder_if_inmemory;
41
+
42
+ impl<S> Database<S>
43
+ where
44
+ S: GraphStorage + GraphStorageMut + Any + Clone + Send + Sync + 'static,
45
+ {
46
+ /// Single-writer auto-commit write path. Takes the writer mutex,
47
+ /// mutates the live store in place via `Arc::make_mut`, and (for
48
+ /// WAL-backed databases) appends a single batched commit record.
49
+ pub(crate) fn execute_mutating_optimistic(
50
+ &self,
51
+ params: BTreeMap<String, LoraValue>,
52
+ deadline: Option<Instant>,
53
+ compiled: &Arc<CompiledQuery>,
54
+ ) -> Result<Vec<Row>> {
55
+ // Serialize commit ordering so WAL records appear in the same
56
+ // order writers publish to the live store.
57
+ let _commit_lock = self
58
+ .writer
59
+ .lock()
60
+ .unwrap_or_else(|poisoned| poisoned.into_inner());
61
+
62
+ // Buffer mutation events tx-locally. We replay them into the
63
+ // durable WAL only after the executor returns success — a
64
+ // failed query leaves no on-disk trace.
65
+ let buffer = Arc::new(Mutex::new(Vec::<MutationEvent>::new()));
66
+ let buffering_rec: Arc<dyn MutationRecorder> =
67
+ Arc::new(BufferingRecorder::new(buffer.clone()));
68
+
69
+ let mut handle = self.store.write();
70
+
71
+ // Install the buffering recorder *after* `make_mut` so the
72
+ // (rare) CoW clone that `make_mut` performs when concurrent
73
+ // readers hold a snapshot doesn't drop the recorder we just
74
+ // installed — `InMemoryGraph::clone` intentionally drops the
75
+ // recorder on the cloned copy.
76
+ let exec_result = {
77
+ let staged = handle.as_mut();
78
+ install_recorder_if_inmemory(staged, Some(buffering_rec));
79
+ let mut executor = MutableExecutor::with_deadline(
80
+ MutableExecutionContext {
81
+ storage: staged,
82
+ params,
83
+ },
84
+ deadline,
85
+ );
86
+ let r = executor.execute_compiled_rows(compiled);
87
+ install_recorder_if_inmemory(staged, None);
88
+ r
89
+ };
90
+
91
+ let rows = match exec_result {
92
+ Ok(rows) => rows,
93
+ Err(e) => return Err(anyhow::Error::from(e)),
94
+ };
95
+
96
+ let events: Vec<MutationEvent> = std::mem::take(&mut buffer.lock().unwrap());
97
+
98
+ if events.is_empty() {
99
+ // Mutating-shape query that didn't actually mutate
100
+ // (e.g., MATCH that found nothing to SET). Reinstall the
101
+ // durable recorder if there is one, then return.
102
+ if let Some(rec) = self.wal.as_ref() {
103
+ let staged = handle.as_mut();
104
+ install_recorder_if_inmemory(
105
+ staged,
106
+ Some(rec.clone() as Arc<dyn MutationRecorder>),
107
+ );
108
+ }
109
+ return Ok(rows);
110
+ }
111
+
112
+ // Durable WAL append. WAL goes first so a crash between WAL
113
+ // and the in-memory state stays recoverable: the next boot
114
+ // replays our events on top of the snapshot.
115
+ let mut wrote_commit = false;
116
+ if let Some(rec) = self.wal.as_ref() {
117
+ ensure_wal_query_can_start(rec)?;
118
+ wrote_commit = rec.commit_events(events)?.wrote();
119
+ }
120
+
121
+ // Reinstall the durable recorder so the post-publish live
122
+ // store keeps observing future mutations.
123
+ if let Some(rec) = self.wal.as_ref() {
124
+ let staged = handle.as_mut();
125
+ install_recorder_if_inmemory(staged, Some(rec.clone() as Arc<dyn MutationRecorder>));
126
+ }
127
+
128
+ if wrote_commit {
129
+ if let Some(rec) = self.wal.as_ref() {
130
+ let live = handle.snapshot();
131
+ self.observe_snapshot_commit_if_needed(&*live, rec)?;
132
+ }
133
+ }
134
+
135
+ Ok(rows)
136
+ }
137
+ }
@@ -0,0 +1,144 @@
1
+ //! Mutation-event replay helpers used by recovery and any caller that
2
+ //! needs to apply a stream of [`MutationEvent`]s against a graph.
3
+ //!
4
+ //! Two concerns live here:
5
+ //!
6
+ //! * [`install_recorder_if_inmemory`] — best-effort attach/detach of a
7
+ //! [`MutationRecorder`] when the storage happens to be `InMemoryGraph`.
8
+ //! * [`replay_into`] — the WAL-recovery replay entry point: applies a
9
+ //! committed event stream to a fresh graph using id-preserving
10
+ //! create paths, with descriptive errors keyed by event index.
11
+
12
+ use std::any::Any;
13
+ use std::sync::Arc;
14
+
15
+ use anyhow::{anyhow, Result};
16
+
17
+ use lora_store::{GraphStorage, GraphStorageMut, InMemoryGraph, MutationEvent, MutationRecorder};
18
+
19
+ /// Best-effort: install a mutation recorder on the storage when the
20
+ /// concrete type is `InMemoryGraph`. The WAL's recorder lives on the
21
+ /// store, but `GraphStorage` is an open trait — backends that don't
22
+ /// support recorders are simply skipped (their writes go unobserved
23
+ /// for WAL purposes, which is correct because they don't drive the WAL
24
+ /// in the first place).
25
+ pub(crate) fn install_recorder_if_inmemory<S: GraphStorage + Any + Sized>(
26
+ store: &mut S,
27
+ recorder: Option<Arc<dyn MutationRecorder>>,
28
+ ) {
29
+ let any: &mut dyn Any = store;
30
+ if let Some(graph) = any.downcast_mut::<InMemoryGraph>() {
31
+ graph.set_mutation_recorder(recorder);
32
+ }
33
+ }
34
+
35
+ /// Apply a `MutationEvent` stream to an in-memory graph by dispatching
36
+ /// each variant to the matching store operation.
37
+ ///
38
+ /// Creation events are replayed through id-preserving paths, not the
39
+ /// normal allocator-backed mutation methods. That matters after aborted
40
+ /// transactions: an aborted create can consume id `N` in the original
41
+ /// process, be dropped by replay, and leave the next committed create at
42
+ /// id `N + 1`. Reusing the regular allocator would shift ids downward.
43
+ ///
44
+ /// Replay must be invoked **before** the `WalRecorder` is installed
45
+ /// on the graph. Otherwise the replay's own mutations would fire the
46
+ /// recorder and re-write the same events to the WAL, doubling them on
47
+ /// the next recovery.
48
+ pub(crate) fn replay_into(graph: &mut InMemoryGraph, events: Vec<MutationEvent>) -> Result<()> {
49
+ for (idx, event) in events.into_iter().enumerate() {
50
+ match event {
51
+ MutationEvent::CreateNode {
52
+ id,
53
+ labels,
54
+ properties,
55
+ } => {
56
+ graph
57
+ .replay_create_node(id, labels, properties)
58
+ .map_err(|e| anyhow!("WAL replay failed at event {idx}: {e}"))?;
59
+ }
60
+ MutationEvent::CreateRelationship {
61
+ id,
62
+ src,
63
+ dst,
64
+ rel_type,
65
+ properties,
66
+ } => {
67
+ graph
68
+ .replay_create_relationship(id, src, dst, &rel_type, properties)
69
+ .map_err(|e| anyhow!("WAL replay failed at event {idx}: {e}"))?;
70
+ }
71
+ MutationEvent::SetNodeProperty {
72
+ node_id,
73
+ key,
74
+ value,
75
+ } => {
76
+ if !graph.set_node_property(node_id, key, value) {
77
+ return Err(anyhow!(
78
+ "WAL replay failed at event {idx}: missing node {node_id} for property set"
79
+ ));
80
+ }
81
+ }
82
+ MutationEvent::RemoveNodeProperty { node_id, key } => {
83
+ if !graph.remove_node_property(node_id, &key) {
84
+ return Err(anyhow!(
85
+ "WAL replay failed at event {idx}: missing node {node_id} for property removal"
86
+ ));
87
+ }
88
+ }
89
+ MutationEvent::AddNodeLabel { node_id, label } => {
90
+ if !graph.add_node_label(node_id, &label) {
91
+ return Err(anyhow!(
92
+ "WAL replay failed at event {idx}: missing node {node_id} for label add"
93
+ ));
94
+ }
95
+ }
96
+ MutationEvent::RemoveNodeLabel { node_id, label } => {
97
+ if !graph.remove_node_label(node_id, &label) {
98
+ return Err(anyhow!(
99
+ "WAL replay failed at event {idx}: missing node {node_id} for label removal"
100
+ ));
101
+ }
102
+ }
103
+ MutationEvent::SetRelationshipProperty { rel_id, key, value } => {
104
+ if !graph.set_relationship_property(rel_id, key, value) {
105
+ return Err(anyhow!(
106
+ "WAL replay failed at event {idx}: missing relationship {rel_id} for property set"
107
+ ));
108
+ }
109
+ }
110
+ MutationEvent::RemoveRelationshipProperty { rel_id, key } => {
111
+ if !graph.remove_relationship_property(rel_id, &key) {
112
+ return Err(anyhow!(
113
+ "WAL replay failed at event {idx}: missing relationship {rel_id} for property removal"
114
+ ));
115
+ }
116
+ }
117
+ MutationEvent::DeleteRelationship { rel_id } => {
118
+ if !graph.delete_relationship(rel_id) {
119
+ return Err(anyhow!(
120
+ "WAL replay failed at event {idx}: missing relationship {rel_id} for delete"
121
+ ));
122
+ }
123
+ }
124
+ MutationEvent::DeleteNode { node_id } => {
125
+ if !graph.delete_node(node_id) {
126
+ return Err(anyhow!(
127
+ "WAL replay failed at event {idx}: missing or attached node {node_id} for delete"
128
+ ));
129
+ }
130
+ }
131
+ MutationEvent::DetachDeleteNode { node_id } => {
132
+ // After the cascading DeleteRelationship +
133
+ // DeleteNode events have already replayed, the node
134
+ // is gone and this becomes a no-op. Calling it
135
+ // anyway is harmless.
136
+ graph.detach_delete_node(node_id);
137
+ }
138
+ MutationEvent::Clear => {
139
+ graph.clear();
140
+ }
141
+ }
142
+ }
143
+ Ok(())
144
+ }
@@ -17,6 +17,7 @@
17
17
  mod database;
18
18
  mod error;
19
19
  mod explain;
20
+ mod live_store;
20
21
  mod named;
21
22
  mod plan_cache;
22
23
  mod snapshot;