supertable 2.2.1__tar.gz → 2.2.3__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 (184) hide show
  1. {supertable-2.2.1/supertable.egg-info → supertable-2.2.3}/PKG-INFO +1 -1
  2. {supertable-2.2.1 → supertable-2.2.3}/pyproject.toml +1 -1
  3. {supertable-2.2.1 → supertable-2.2.3}/setup.py +1 -1
  4. {supertable-2.2.1 → supertable-2.2.3}/supertable/__init__.py +1 -1
  5. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/settings.py +0 -22
  6. {supertable-2.2.1 → supertable-2.2.3}/supertable/data_writer.py +42 -98
  7. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/defaults.py +1 -1
  8. {supertable-2.2.1 → supertable-2.2.3}/supertable/processing.py +280 -171
  9. {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_catalog.py +1 -6
  10. {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_keys.py +0 -77
  11. {supertable-2.2.1 → supertable-2.2.3}/supertable/simple_table.py +29 -18
  12. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_compact.py +3 -82
  13. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_newer_than.py +1 -1
  14. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_process_delete_only.py +2 -2
  15. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_redis_key_prefix.py +0 -21
  16. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_small_file_compaction.py +2 -2
  17. supertable-2.2.3/supertable/utils/profiler.py +116 -0
  18. {supertable-2.2.1 → supertable-2.2.3/supertable.egg-info}/PKG-INFO +1 -1
  19. {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/SOURCES.txt +1 -7
  20. supertable-2.2.1/supertable/gc/__init__.py +0 -26
  21. supertable-2.2.1/supertable/gc/cleaner.py +0 -258
  22. supertable-2.2.1/supertable/gc/daemon.py +0 -284
  23. supertable-2.2.1/supertable/gc/queue.py +0 -221
  24. supertable-2.2.1/supertable/tests/test_gc_cleaner.py +0 -330
  25. supertable-2.2.1/supertable/tests/test_gc_daemon.py +0 -251
  26. supertable-2.2.1/supertable/tests/test_gc_queue.py +0 -331
  27. {supertable-2.2.1 → supertable-2.2.3}/LICENSE +0 -0
  28. {supertable-2.2.1 → supertable-2.2.3}/README.md +0 -0
  29. {supertable-2.2.1 → supertable-2.2.3}/requirements.txt +0 -0
  30. {supertable-2.2.1 → supertable-2.2.3}/setup.cfg +0 -0
  31. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/__init__.py +0 -0
  32. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/admin.py +0 -0
  33. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/chain.py +0 -0
  34. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/consumers.py +0 -0
  35. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/crypto.py +0 -0
  36. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/events.py +0 -0
  37. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/export.py +0 -0
  38. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/logger.py +0 -0
  39. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/middleware.py +0 -0
  40. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/reader.py +0 -0
  41. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/retention.py +0 -0
  42. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/__init__.py +0 -0
  43. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_chain.py +0 -0
  44. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_crypto.py +0 -0
  45. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_emit.py +0 -0
  46. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_events.py +0 -0
  47. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_retention.py +0 -0
  48. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/writer_parquet.py +0 -0
  49. {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/writer_redis.py +0 -0
  50. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/__init__.py +0 -0
  51. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/defaults.py +0 -0
  52. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/homedir.py +0 -0
  53. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/__init__.py +0 -0
  54. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_defaults.py +0 -0
  55. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_homedir.py +0 -0
  56. {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_settings.py +0 -0
  57. {supertable-2.2.1 → supertable-2.2.3}/supertable/data_classes.py +0 -0
  58. {supertable-2.2.1 → supertable-2.2.3}/supertable/data_reader.py +0 -0
  59. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/__init__.py +0 -0
  60. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/__init__.py +0 -0
  61. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/__main__.py +0 -0
  62. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/check_filter_builder.py +0 -0
  63. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/controller.py +0 -0
  64. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/data_writer_helpers.py +0 -0
  65. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/defaults.py +0 -0
  66. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/dummy_data.py +0 -0
  67. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/read_parquet_header.py +0 -0
  68. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_01_01_create_super_table.py +0 -0
  69. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_01_02_enable_mirroring_formats.py +0 -0
  70. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_02_create_roles.py +0 -0
  71. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_03_create_users.py +0 -0
  72. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_01_write_dummy_data.py +0 -0
  73. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_02_write_single_data.py +0 -0
  74. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_03_01_write_staging.py +0 -0
  75. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_03_02_create_pipe.py +0 -0
  76. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_04_01_write_monitoring_simple.py +0 -0
  77. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_04_02_write_monitoring_parallel.py +0 -0
  78. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_05_write_tombstone.py +0 -0
  79. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_01_read_data_error.py +0 -0
  80. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_02_01_read_super_data_ok.py +0 -0
  81. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_02_02_read_table_data_ok.py +0 -0
  82. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_03_read_meta.py +0 -0
  83. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_04_read_staging.py +0 -0
  84. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_06_01_read_roles.py +0 -0
  85. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_06_02_read_user.py +0 -0
  86. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_07_01_estimate_read.py +0 -0
  87. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_07_02_estimate_files.py +0 -0
  88. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_08_read_snapshot_history.py +0 -0
  89. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s04_01_03_delete_pipe.py +0 -0
  90. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s05_01_delete_table.py +0 -0
  91. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s05_02_delete_super_table.py +0 -0
  92. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/__init__.py +0 -0
  93. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/core.py +0 -0
  94. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/generate.py +0 -0
  95. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/load.py +0 -0
  96. {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/topup.py +0 -0
  97. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/__init__.py +0 -0
  98. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/data_estimator.py +0 -0
  99. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/duckdb_lite.py +0 -0
  100. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/duckdb_pro.py +0 -0
  101. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/engine_common.py +0 -0
  102. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/engine_enum.py +0 -0
  103. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/executor.py +0 -0
  104. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/plan_stats.py +0 -0
  105. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/spark_thrift.py +0 -0
  106. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/__init__.py +0 -0
  107. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/conftest.py +0 -0
  108. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/test_dedup_read.py +0 -0
  109. {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/test_engine.py +0 -0
  110. {supertable-2.2.1 → supertable-2.2.3}/supertable/errors.py +0 -0
  111. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/__init__.py +0 -0
  112. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/__init__.py +0 -0
  113. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/benchmark_locking.py +0 -0
  114. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/measure_lock_speed.py +0 -0
  115. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/measure_lock_time.py +0 -0
  116. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/file_lock.py +0 -0
  117. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/redis_lock.py +0 -0
  118. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/__init__.py +0 -0
  119. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/test_file_lock.py +0 -0
  120. {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/test_redis_lock.py +0 -0
  121. {supertable-2.2.1 → supertable-2.2.3}/supertable/logging.py +0 -0
  122. {supertable-2.2.1 → supertable-2.2.3}/supertable/meta_reader.py +0 -0
  123. {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/__init__.py +0 -0
  124. {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_delta.py +0 -0
  125. {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_formats.py +0 -0
  126. {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_iceberg.py +0 -0
  127. {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_parquet.py +0 -0
  128. {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring/__init__.py +0 -0
  129. {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring/partitions.py +0 -0
  130. {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring_writer.py +0 -0
  131. {supertable-2.2.1 → supertable-2.2.3}/supertable/plan_extender.py +0 -0
  132. {supertable-2.2.1 → supertable-2.2.3}/supertable/query_plan_manager.py +0 -0
  133. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/__init__.py +0 -0
  134. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/access_control.py +0 -0
  135. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/filter_builder.py +0 -0
  136. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/permissions.py +0 -0
  137. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/role_manager.py +0 -0
  138. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/row_column_security.py +0 -0
  139. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_filter_builder.py +0 -0
  140. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_rbac.py +0 -0
  141. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_rbac_per_table.py +0 -0
  142. {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/user_manager.py +0 -0
  143. {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_connector.py +0 -0
  144. {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_infra.py +0 -0
  145. {supertable-2.2.1 → supertable-2.2.3}/supertable/staging_area.py +0 -0
  146. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/__init__.py +0 -0
  147. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/azure_storage.py +0 -0
  148. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/gcp_storage.py +0 -0
  149. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/local_storage.py +0 -0
  150. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/minio_storage.py +0 -0
  151. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/s3_storage.py +0 -0
  152. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/storage_factory.py +0 -0
  153. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/storage_interface.py +0 -0
  154. {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/tests/test_storage.py +0 -0
  155. {supertable-2.2.1 → supertable-2.2.3}/supertable/super_pipe.py +0 -0
  156. {supertable-2.2.1 → supertable-2.2.3}/supertable/super_table.py +0 -0
  157. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/__init__.py +0 -0
  158. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_align_to_schema_fix.py +0 -0
  159. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_create_if_missing.py +0 -0
  160. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_reader.py +0 -0
  161. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_reader_preflight.py +0 -0
  162. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer.py +0 -0
  163. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_comprehensive.py +0 -0
  164. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_tombstones.py +0 -0
  165. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_dedup_on_read_write.py +0 -0
  166. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_errors.py +0 -0
  167. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_meta_reader.py +0 -0
  168. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_monitoring_partitions.py +0 -0
  169. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_monitoring_sink_guard.py +0 -0
  170. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_processing.py +0 -0
  171. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_processing_compact_resources.py +0 -0
  172. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_query_sql.py +0 -0
  173. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_simple_table.py +0 -0
  174. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_super_table.py +0 -0
  175. {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_supertable_all.py +0 -0
  176. {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/__init__.py +0 -0
  177. {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/helper.py +0 -0
  178. {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/sql_parser.py +0 -0
  179. {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/tests/test_sql_parser_columns.py +0 -0
  180. {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/timer.py +0 -0
  181. {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/dependency_links.txt +0 -0
  182. {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/entry_points.txt +0 -0
  183. {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/requires.txt +0 -0
  184. {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: supertable
3
- Version: 2.2.1
3
+ Version: 2.2.3
4
4
  Summary: SuperTable — versioned data lake library for SQL analytics on Parquet + Redis.
5
5
  Author: Levente Kupas
6
6
  Author-email: Levente Kupas <lkupas@kladnasoft.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "supertable"
7
- version = "2.2.1"
7
+ version = "2.2.3"
8
8
  description = "SuperTable — versioned data lake library for SQL analytics on Parquet + Redis."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -19,7 +19,7 @@ long_description = readme.read_text(encoding="utf-8") if readme.exists() else ""
19
19
 
20
20
  setup(
21
21
  name="supertable",
22
- version="2.2.1",
22
+ version="2.2.3",
23
23
  description="SuperTable — versioned data lake library for SQL analytics on Parquet + Redis.",
24
24
  long_description=long_description,
25
25
  long_description_content_type="text/markdown",
@@ -25,7 +25,7 @@ See the ``supertable.demo`` package for runnable end-to-end demos and the
25
25
  project documentation for the full API surface.
26
26
  """
27
27
 
28
- __version__ = "2.2.1"
28
+ __version__ = "2.2.3"
29
29
 
30
30
  # Re-export the core public surface so users can do ``from supertable import …``
31
31
  # instead of remembering submodule paths.
@@ -282,21 +282,6 @@ class Settings:
282
282
  SUPERTABLE_SHARE_PRESIGN_TTL: int = 14400 # SUPERTABLE_SHARE_PRESIGN_TTL (seconds, default 4h)
283
283
  SUPERTABLE_SHARE_REFRESH_BUFFER: int = 600 # SUPERTABLE_SHARE_REFRESH_BUFFER (seconds, refresh 10min before expiry)
284
284
 
285
- # ── Storage GC (deferred deletion of sunset parquets + old snapshot JSONs) ──
286
- # Sunset parquet files and old snapshot JSONs are never deleted by the
287
- # writer directly. When either flag is enabled, the writer XADDs paths
288
- # to a per-table Redis STREAM after a successful leaf-CAS. A separate
289
- # cleaner daemon (``python -m supertable.gc.cleaner``) drains entries
290
- # older than ``SUPERTABLE_GC_DELAY_SEC`` and calls ``storage.delete()``.
291
- # The delay window avoids the race where an in-flight reader's
292
- # ``parquet_scan([...])`` resolves a file path right before the writer
293
- # deletes it. Defaults below preserve today's behaviour (off, unlimited).
294
- SUPERTABLE_SNAPSHOT_RETENTION: int = 0 # SUPERTABLE_SNAPSHOT_RETENTION (0 = keep all snapshot JSONs)
295
- SUPERTABLE_SUNSET_GC_ENABLED: bool = False # SUPERTABLE_SUNSET_GC_ENABLED (delete sunset parquets via queue)
296
- SUPERTABLE_GC_DELAY_SEC: int = 1800 # SUPERTABLE_GC_DELAY_SEC (min age before cleaner deletes)
297
- SUPERTABLE_GC_SLEEP_SEC: int = 60 # SUPERTABLE_GC_SLEEP_SEC (cleaner loop sleep)
298
- SUPERTABLE_GC_BATCH_SIZE: int = 500 # SUPERTABLE_GC_BATCH_SIZE (max entries processed per table per tick)
299
-
300
285
 
301
286
  # ── Convenience properties ───────────────────────────────────────
302
287
 
@@ -543,13 +528,6 @@ def _build_settings() -> Settings:
543
528
  # Data Sharing
544
529
  SUPERTABLE_SHARE_PRESIGN_TTL=_env_int("SUPERTABLE_SHARE_PRESIGN_TTL", 14400),
545
530
  SUPERTABLE_SHARE_REFRESH_BUFFER=_env_int("SUPERTABLE_SHARE_REFRESH_BUFFER", 600),
546
-
547
- # ── Storage GC ───────────────────────────────────────────────
548
- SUPERTABLE_SNAPSHOT_RETENTION=_env_int("SUPERTABLE_SNAPSHOT_RETENTION", 0),
549
- SUPERTABLE_SUNSET_GC_ENABLED=_env_bool("SUPERTABLE_SUNSET_GC_ENABLED", False),
550
- SUPERTABLE_GC_DELAY_SEC=_env_int("SUPERTABLE_GC_DELAY_SEC", 1800),
551
- SUPERTABLE_GC_SLEEP_SEC=_env_int("SUPERTABLE_GC_SLEEP_SEC", 60),
552
- SUPERTABLE_GC_BATCH_SIZE=_env_int("SUPERTABLE_GC_BATCH_SIZE", 500),
553
531
  )
554
532
 
555
533
 
@@ -13,13 +13,13 @@ from polars import DataFrame
13
13
  from supertable.config.defaults import logger
14
14
  from supertable.config.settings import settings
15
15
  from supertable.errors import SuperTableNotFoundError, TableNotFoundError
16
- from supertable.gc.queue import collect_old_snapshot_paths, enqueue_deletions
17
16
  from supertable.monitoring.partitions import MONITORING_SINK_TABLES
18
17
  from supertable.monitoring_writer import MonitoringWriter # async monitoring
19
18
  from supertable.super_table import SuperTable
20
19
  from supertable import redis_keys as RK
21
20
  from supertable.simple_table import SimpleTable
22
21
  from supertable.utils.timer import Timer
22
+ from supertable.utils.profiler import Profiler
23
23
  from supertable.processing import (
24
24
  process_overlapping_files,
25
25
  process_delete_only,
@@ -277,7 +277,11 @@ class DataWriter:
277
277
 
278
278
  t0 = time.time()
279
279
  t_last = t0
280
- timings = {}
280
+ profiler = Profiler()
281
+ # Convenience view: top-level stages still indexed by the original
282
+ # short names ("lock", "snapshot", "overlap", ...) so the existing
283
+ # log line keeps working unchanged.
284
+ timings = profiler.timings
281
285
 
282
286
  def mark(stage: str):
283
287
  nonlocal t_last
@@ -338,6 +342,7 @@ class DataWriter:
338
342
  overlapping_files = find_overlapping_files(
339
343
  last_simple_table, dataframe, overwrite_columns, locking=None,
340
344
  table_config=table_config,
345
+ profiler=profiler,
341
346
  )
342
347
  mark("overlap")
343
348
 
@@ -354,6 +359,7 @@ class DataWriter:
354
359
  overwrite_columns=overwrite_columns,
355
360
  newer_than_col=newer_than,
356
361
  file_cache=file_cache,
362
+ profiler=profiler,
357
363
  )
358
364
  skipped = pre_filter_count - dataframe.height
359
365
  if skipped > 0:
@@ -385,6 +391,8 @@ class DataWriter:
385
391
  "skipped_stale": skipped,
386
392
  "lineage": _safe_json(lineage or {}),
387
393
  "duration": round(time.time() - t0, 6),
394
+ "timings": profiler.emit_timings(),
395
+ "counts": profiler.emit_counts(),
388
396
  }
389
397
  # Don't return here — fall through to finally (lock release)
390
398
  # and the post-finally monitoring block. Returning inside the
@@ -431,6 +439,7 @@ class DataWriter:
431
439
  data_dir=simple_table.data_dir,
432
440
  compression_level=compression_level,
433
441
  table_config=table_config,
442
+ profiler=profiler,
434
443
  )
435
444
  new_resources = compact_resources
436
445
  sunset_files = compact_sunset
@@ -474,6 +483,7 @@ class DataWriter:
474
483
  simple_table.data_dir,
475
484
  compression_level,
476
485
  file_cache=file_cache,
486
+ profiler=profiler,
477
487
  )
478
488
  else:
479
489
  inserted, deleted, total_rows, total_columns, new_resources, sunset_files = process_overlapping_files(
@@ -484,6 +494,7 @@ class DataWriter:
484
494
  compression_level,
485
495
  file_cache=file_cache,
486
496
  table_config=table_config,
497
+ profiler=profiler,
487
498
  )
488
499
  mark("process")
489
500
 
@@ -514,6 +525,7 @@ class DataWriter:
514
525
  last_snapshot=last_simple_table,
515
526
  last_snapshot_path=last_simple_table_path,
516
527
  lineage=eff_lineage,
528
+ profiler=profiler,
517
529
  )
518
530
  mark("update_simple")
519
531
 
@@ -534,67 +546,29 @@ class DataWriter:
534
546
  ],
535
547
  }
536
548
 
537
- try:
538
- self.catalog.set_leaf_payload_cas(
539
- self.super_table.organization,
540
- self.super_table.super_name,
541
- simple_name,
542
- payload,
543
- new_snapshot_path,
544
- now_ms=now_ms,
545
- )
546
- except Exception:
547
- # Backward compatible fallback.
548
- self.catalog.set_leaf_path_cas(
549
- self.super_table.organization,
550
- self.super_table.super_name,
551
- simple_name,
552
- new_snapshot_path,
553
- now_ms=now_ms,
554
- )
555
-
556
- self.catalog.bump_root(self.super_table.organization, self.super_table.super_name, now_ms=now_ms)
557
- mark("bump_root")
558
-
559
- # --- Enqueue deferred deletions (post-CAS, post-bump) ----------
560
- # Strict ordering matters: leaf-CAS + root-bump have committed
561
- # the new snapshot as the authoritative state. Only NOW is it
562
- # safe to schedule physical deletion of files that the old
563
- # snapshot still references — any reader that loaded the
564
- # previous leaf payload will finish before the cleaner's delay
565
- # window expires.
566
- #
567
- # Both blocks are best-effort: enqueue_deletions and
568
- # collect_old_snapshot_paths swallow Redis/storage errors and
569
- # log a warning. A GC failure must never fail the write.
570
- try:
571
- _org = self.super_table.organization
572
- _sup = self.super_table.super_name
573
- if settings.SUPERTABLE_SUNSET_GC_ENABLED and sunset_files:
574
- enqueue_deletions(
575
- self.catalog,
576
- _org, _sup, simple_name,
577
- "parquet",
578
- list(sunset_files),
579
- write_id=qid,
549
+ with profiler.span("redis.set_leaf"):
550
+ try:
551
+ self.catalog.set_leaf_payload_cas(
552
+ self.super_table.organization,
553
+ self.super_table.super_name,
554
+ simple_name,
555
+ payload,
556
+ new_snapshot_path,
557
+ now_ms=now_ms,
580
558
  )
581
- if settings.SUPERTABLE_SNAPSHOT_RETENTION > 0:
582
- old_paths = collect_old_snapshot_paths(
583
- new_snapshot_dict,
584
- self.super_table.storage,
585
- settings.SUPERTABLE_SNAPSHOT_RETENTION,
559
+ except Exception:
560
+ # Backward compatible fallback.
561
+ self.catalog.set_leaf_path_cas(
562
+ self.super_table.organization,
563
+ self.super_table.super_name,
564
+ simple_name,
565
+ new_snapshot_path,
566
+ now_ms=now_ms,
586
567
  )
587
- if old_paths:
588
- enqueue_deletions(
589
- self.catalog,
590
- _org, _sup, simple_name,
591
- "snapshot",
592
- old_paths,
593
- write_id=qid,
594
- )
595
- except Exception as e:
596
- logger.warning(lp(f"GC enqueue failed (write still succeeded): {e}"))
597
- mark("gc_enqueue")
568
+
569
+ with profiler.span("redis.bump_root"):
570
+ self.catalog.bump_root(self.super_table.organization, self.super_table.super_name, now_ms=now_ms)
571
+ mark("bump_root")
598
572
 
599
573
  # --- Store schema + table name in Redis (permanent, not cache) ---
600
574
  try:
@@ -649,6 +623,8 @@ class DataWriter:
649
623
  "skipped_stale": 0,
650
624
  "lineage": _safe_json(lineage or {}),
651
625
  "duration": round(time.time() - t0, 6),
626
+ "timings": profiler.emit_timings(),
627
+ "counts": profiler.emit_counts(),
652
628
  }
653
629
  mark("prepare_monitor")
654
630
 
@@ -977,12 +953,10 @@ class DataWriter:
977
953
  # Critical filter: a file produced by Phase A (tombstone
978
954
  # compaction) can be picked up as a small-file candidate
979
955
  # by Phase B (compact_resources) and then sunset there.
980
- # If we leave it in ``all_new_resources`` it lands in the
981
- # new snapshot **and** in ``all_sunset`` (slated for GC
982
- # deletion). 30 min later GC deletes the file while the
983
- # snapshot still references it readers fail with
984
- # FileNotFoundError. Filter the file out of new_resources
985
- # when it also appears in any sunset set.
956
+ # If we leave it in ``all_new_resources`` it would land in the
957
+ # new snapshot **and** in ``all_sunset`` at the same time.
958
+ # Filter the file out of new_resources when it also appears
959
+ # in any sunset set so the snapshot stays consistent.
986
960
  all_sunset = set(tomb_sunset) | set(small_sunset)
987
961
  all_new_resources = [
988
962
  r for r in (list(tomb_new_resources) + list(small_new_resources))
@@ -994,7 +968,7 @@ class DataWriter:
994
968
  result["total_rows_written"] = small_total_rows
995
969
 
996
970
  # Short-circuit: nothing to do, skip the snapshot rewrite
997
- # and the leaf-CAS / root-bump / GC / mirror path. BUT do
971
+ # and the leaf-CAS / root-bump / mirror path. BUT do
998
972
  # NOT return here — execution must fall through to the
999
973
  # ``finally`` (which releases the lock) AND the monitoring
1000
974
  # + audit emission blocks after the try/finally so the
@@ -1098,36 +1072,6 @@ class DataWriter:
1098
1072
  )
1099
1073
  mark("bump_root")
1100
1074
 
1101
- # --- GC enqueue (same flags as write) ----------------------------
1102
- try:
1103
- _org = self.super_table.organization
1104
- _sup = self.super_table.super_name
1105
- if settings.SUPERTABLE_SUNSET_GC_ENABLED and all_sunset:
1106
- enqueue_deletions(
1107
- self.catalog,
1108
- _org, _sup, simple_name,
1109
- "parquet",
1110
- list(all_sunset),
1111
- write_id=qid,
1112
- )
1113
- if settings.SUPERTABLE_SNAPSHOT_RETENTION > 0:
1114
- old_paths = collect_old_snapshot_paths(
1115
- new_snapshot_dict,
1116
- self.super_table.storage,
1117
- settings.SUPERTABLE_SNAPSHOT_RETENTION,
1118
- )
1119
- if old_paths:
1120
- enqueue_deletions(
1121
- self.catalog,
1122
- _org, _sup, simple_name,
1123
- "snapshot",
1124
- old_paths,
1125
- write_id=qid,
1126
- )
1127
- except Exception as e:
1128
- logger.warning(lp(f"GC enqueue failed (compact still succeeded): {e}"))
1129
- mark("gc_enqueue")
1130
-
1131
1075
  # --- Mirroring ---------------------------------------------------
1132
1076
  try:
1133
1077
  MirrorFormats.mirror_if_enabled(
@@ -10,7 +10,7 @@ Used by:
10
10
 
11
11
  # --- SuperTable connection settings ---
12
12
  organization: str = "kladna-soft"
13
- super_name: str = "example"
13
+ super_name: str = "webshop"
14
14
  role_name: str = "superadmin"
15
15
 
16
16
  # --- Data generation / loading settings ---