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.
- {supertable-2.2.1/supertable.egg-info → supertable-2.2.3}/PKG-INFO +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/pyproject.toml +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/setup.py +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/supertable/__init__.py +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/settings.py +0 -22
- {supertable-2.2.1 → supertable-2.2.3}/supertable/data_writer.py +42 -98
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/defaults.py +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/supertable/processing.py +280 -171
- {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_catalog.py +1 -6
- {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_keys.py +0 -77
- {supertable-2.2.1 → supertable-2.2.3}/supertable/simple_table.py +29 -18
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_compact.py +3 -82
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_newer_than.py +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_process_delete_only.py +2 -2
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_redis_key_prefix.py +0 -21
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_small_file_compaction.py +2 -2
- supertable-2.2.3/supertable/utils/profiler.py +116 -0
- {supertable-2.2.1 → supertable-2.2.3/supertable.egg-info}/PKG-INFO +1 -1
- {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/SOURCES.txt +1 -7
- supertable-2.2.1/supertable/gc/__init__.py +0 -26
- supertable-2.2.1/supertable/gc/cleaner.py +0 -258
- supertable-2.2.1/supertable/gc/daemon.py +0 -284
- supertable-2.2.1/supertable/gc/queue.py +0 -221
- supertable-2.2.1/supertable/tests/test_gc_cleaner.py +0 -330
- supertable-2.2.1/supertable/tests/test_gc_daemon.py +0 -251
- supertable-2.2.1/supertable/tests/test_gc_queue.py +0 -331
- {supertable-2.2.1 → supertable-2.2.3}/LICENSE +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/README.md +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/requirements.txt +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/setup.cfg +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/admin.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/chain.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/consumers.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/crypto.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/events.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/export.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/logger.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/middleware.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/reader.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/retention.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_chain.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_crypto.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_emit.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_events.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/tests/test_retention.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/writer_parquet.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/audit/writer_redis.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/defaults.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/homedir.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_defaults.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_homedir.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/config/tests/test_settings.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/data_classes.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/data_reader.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/__main__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/check_filter_builder.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/controller.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/data_writer_helpers.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/defaults.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/dummy_data.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/read_parquet_header.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_01_01_create_super_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_01_02_enable_mirroring_formats.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_02_create_roles.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s01_03_create_users.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_01_write_dummy_data.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_02_write_single_data.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_03_01_write_staging.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_03_02_create_pipe.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_04_01_write_monitoring_simple.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_04_02_write_monitoring_parallel.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s02_05_write_tombstone.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_01_read_data_error.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_02_01_read_super_data_ok.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_02_02_read_table_data_ok.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_03_read_meta.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_04_read_staging.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_06_01_read_roles.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_06_02_read_user.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_07_01_estimate_read.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_07_02_estimate_files.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s03_08_read_snapshot_history.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s04_01_03_delete_pipe.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s05_01_delete_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/quickstart/s05_02_delete_super_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/core.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/generate.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/load.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/demo/webshop/topup.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/data_estimator.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/duckdb_lite.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/duckdb_pro.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/engine_common.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/engine_enum.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/executor.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/plan_stats.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/spark_thrift.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/conftest.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/test_dedup_read.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/engine/tests/test_engine.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/errors.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/benchmark_locking.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/measure_lock_speed.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/benchmarks/measure_lock_time.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/file_lock.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/redis_lock.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/test_file_lock.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/locking/tests/test_redis_lock.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/logging.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/meta_reader.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_delta.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_formats.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_iceberg.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/mirroring/mirror_parquet.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring/partitions.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/monitoring_writer.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/plan_extender.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/query_plan_manager.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/access_control.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/filter_builder.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/permissions.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/role_manager.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/row_column_security.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_filter_builder.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_rbac.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/tests/test_rbac_per_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/rbac/user_manager.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_connector.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/redis_infra.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/staging_area.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/azure_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/gcp_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/local_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/minio_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/s3_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/storage_factory.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/storage_interface.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/storage/tests/test_storage.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/super_pipe.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/super_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_align_to_schema_fix.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_create_if_missing.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_reader.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_reader_preflight.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_comprehensive.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_data_writer_tombstones.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_dedup_on_read_write.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_errors.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_meta_reader.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_monitoring_partitions.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_monitoring_sink_guard.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_processing.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_processing_compact_resources.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_query_sql.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_simple_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_super_table.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/tests/test_supertable_all.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/__init__.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/helper.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/sql_parser.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/tests/test_sql_parser_columns.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable/utils/timer.py +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/dependency_links.txt +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/entry_points.txt +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/requires.txt +0 -0
- {supertable-2.2.1 → supertable-2.2.3}/supertable.egg-info/top_level.txt +0 -0
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
538
|
-
|
|
539
|
-
self.
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
self.super_table.
|
|
585
|
-
|
|
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
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
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
|
|
981
|
-
# new snapshot **and** in ``all_sunset``
|
|
982
|
-
#
|
|
983
|
-
#
|
|
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 /
|
|
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(
|