pg_eventstore 1.13.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +11 -2
- data/CHANGELOG.md +195 -16
- data/README.md +33 -10
- data/db/migrations/10_setup_pg_cron.rb +1 -0
- data/db/migrations/11_add_events_link_global_position.sql +1 -0
- data/db/migrations/12_migrate_legacy_links.rb +83 -0
- data/db/migrations/13_remove_events_link_id.sql +6 -0
- data/db/migrations/14_remove_ids_events_id_index.sql +1 -0
- data/db/migrations/15_create_streams_global_index.sql +17 -0
- data/db/migrations/16_populate_streams_global_index.rb +150 -0
- data/db/migrations/17_create_events_global_index.sql +62 -0
- data/db/migrations/18_populate_events_global_index.rb +124 -0
- data/db/migrations/19_populate_events_global_index_p2.rb +25 -0
- data/db/migrations/20_migrate_subscriptions_current_position.sql +19 -0
- data/db/migrations/21_create_partitions_stats.sql +2 -0
- data/db/migrations/22_drop_streams_sql_view.sql +2 -0
- data/db/migrations/23_adjust_partitions_indexes.sql +5 -0
- data/db/migrations/24_drop_legacy_events_indexes.sql +3 -0
- data/db/migrations/25_add_parent_partitions_info_to_partitions.sql +16 -0
- data/db/migrations/26_change_events_stream_revision_type.rb +35 -0
- data/db/migrations/27_drop_events_horizon.sql +3 -0
- data/db/migrations/28_create_maintenance_tasks.sql +8 -0
- data/db/migrations/29_create_event_markers.sql +35 -0
- data/db/migrations/30_improve_partitions_search_in_admin_ui.rb +24 -0
- data/db/migrations/31_drop_events_id_default_value.sql +1 -0
- data/db/migrations/32_create_parittions_triggers.sql +101 -0
- data/db/migrations/9_create_events_horizon.sql +21 -0
- data/docs/AGENTS.fragment.md +696 -0
- data/docs/admin_ui.md +3 -1
- data/docs/appending_events.md +110 -49
- data/docs/configuration.md +69 -36
- data/docs/event_tracing.md +55 -0
- data/docs/events_and_streams.md +54 -30
- data/docs/how_it_works.md +57 -16
- data/docs/linking_events.md +2 -1
- data/docs/maintenance.md +14 -5
- data/docs/multiple_commands.md +30 -6
- data/docs/reading_events.md +208 -43
- data/docs/reading_streams.md +50 -0
- data/docs/replication.md +99 -0
- data/docs/subscriptions.md +165 -35
- data/docs/writing_middleware.md +25 -8
- data/ext/pg_eventstore_ext/extconf.rb +5 -0
- data/ext/pg_eventstore_ext/pg_eventstore_ext.c +74 -0
- data/lib/pg_eventstore/async_runner.rb +63 -0
- data/lib/pg_eventstore/basic_config.rb +15 -0
- data/lib/pg_eventstore/callbacks.rb +7 -5
- data/lib/pg_eventstore/chunks/chunk.rb +31 -0
- data/lib/pg_eventstore/chunks/read_api_events_index_chunk.rb +83 -0
- data/lib/pg_eventstore/chunks/replica_events_index_chunk.rb +35 -0
- data/lib/pg_eventstore/chunks/repository.rb +73 -0
- data/lib/pg_eventstore/chunks/subscription_checkpoint_chunk.rb +48 -0
- data/lib/pg_eventstore/chunks/subscription_events_index_chunk.rb +99 -0
- data/lib/pg_eventstore/chunks.rb +14 -0
- data/lib/pg_eventstore/cli/try_to_delete_subscriptions_set.rb +2 -2
- data/lib/pg_eventstore/client.rb +167 -52
- data/lib/pg_eventstore/commands/append.rb +62 -43
- data/lib/pg_eventstore/commands/delete_event.rb +7 -8
- data/lib/pg_eventstore/commands/delete_stream.rb +3 -3
- data/lib/pg_eventstore/commands/event_modifiers/prepare_link_event.rb +11 -6
- data/lib/pg_eventstore/commands/event_modifiers/prepare_regular_event.rb +12 -7
- data/lib/pg_eventstore/commands/link_to.rb +9 -9
- data/lib/pg_eventstore/commands/multiple.rb +2 -2
- data/lib/pg_eventstore/commands/read.rb +23 -5
- data/lib/pg_eventstore/commands/read_grouped.rb +46 -0
- data/lib/pg_eventstore/commands/read_streams.rb +18 -0
- data/lib/pg_eventstore/commands/read_streams_paginated.rb +56 -0
- data/lib/pg_eventstore/commands/regular_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands/revision_check/current_revision.rb +51 -0
- data/lib/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rb +46 -0
- data/lib/pg_eventstore/commands/revision_check/expected_revision.rb +135 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_check.rb +98 -0
- data/lib/pg_eventstore/commands/revision_check/stream_revision_comparison.rb +36 -0
- data/lib/pg_eventstore/commands/stream_revision.rb +14 -0
- data/lib/pg_eventstore/commands/system_stream_read_paginated.rb +4 -4
- data/lib/pg_eventstore/commands.rb +4 -2
- data/lib/pg_eventstore/config.rb +30 -9
- data/lib/pg_eventstore/connection.rb +22 -37
- data/lib/pg_eventstore/errors.rb +137 -11
- data/lib/pg_eventstore/event.rb +39 -7
- data/lib/pg_eventstore/event_deserializer.rb +5 -4
- data/lib/pg_eventstore/event_global_index.rb +118 -0
- data/lib/pg_eventstore/event_marker.rb +16 -0
- data/lib/pg_eventstore/event_marker_index.rb +25 -0
- data/lib/pg_eventstore/event_serializer.rb +6 -0
- data/lib/pg_eventstore/extensions/acts_as_configurable.rb +88 -0
- data/lib/pg_eventstore/extensions/options_defaults.rb +25 -0
- data/lib/pg_eventstore/extensions/options_extension.rb +42 -13
- data/lib/pg_eventstore/feature_marker.rb +18 -0
- data/lib/pg_eventstore/maintenance.rb +11 -6
- data/lib/pg_eventstore/middleware/event_tracing.rb +53 -0
- data/lib/pg_eventstore/partition.rb +6 -0
- data/lib/pg_eventstore/pg_connection.rb +70 -14
- data/lib/pg_eventstore/queries/event_marker_queries.rb +74 -0
- data/lib/pg_eventstore/queries/event_queries.rb +9 -95
- data/lib/pg_eventstore/queries/events_global_index_queries.rb +131 -0
- data/lib/pg_eventstore/queries/index_filtering_queries.rb +179 -0
- data/lib/pg_eventstore/queries/links_resolver.rb +10 -7
- data/lib/pg_eventstore/queries/maintenance_queries.rb +159 -42
- data/lib/pg_eventstore/queries/partition_queries.rb +46 -104
- data/lib/pg_eventstore/queries/replica_queries.rb +110 -0
- data/lib/pg_eventstore/queries/streams_global_index_queries.rb +163 -0
- data/lib/pg_eventstore/queries/transaction_queries.rb +58 -10
- data/lib/pg_eventstore/queries.rb +29 -1
- data/lib/pg_eventstore/query_builders/basic_filtering.rb +38 -5
- data/lib/pg_eventstore/query_builders/event_markers_filtering.rb +47 -0
- data/lib/pg_eventstore/query_builders/event_markers_index_filtering.rb +275 -0
- data/lib/pg_eventstore/query_builders/event_subscription_positions_filtering.rb +37 -0
- data/lib/pg_eventstore/query_builders/events_filtering.rb +15 -164
- data/lib/pg_eventstore/query_builders/events_global_index_filtering.rb +227 -0
- data/lib/pg_eventstore/query_builders/filters/collection.rb +324 -0
- data/lib/pg_eventstore/query_builders/filters/event_type_filter.rb +37 -0
- data/lib/pg_eventstore/query_builders/filters/filter_row.rb +54 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter.rb +20 -0
- data/lib/pg_eventstore/query_builders/filters/marker_filter_row.rb +49 -0
- data/lib/pg_eventstore/query_builders/filters/stream_filter.rb +48 -0
- data/lib/pg_eventstore/query_builders/index_based_events_filtering.rb +260 -0
- data/lib/pg_eventstore/query_builders/partitions_filtering.rb +175 -51
- data/lib/pg_eventstore/query_builders/read_cursor/stream_cursor.rb +122 -0
- data/lib/pg_eventstore/query_builders/streams_global_index_filtering.rb +83 -0
- data/lib/pg_eventstore/query_builders/subscription_events_filtering.rb +79 -0
- data/lib/pg_eventstore/query_strategy/async.rb +64 -0
- data/lib/pg_eventstore/query_strategy/foreground.rb +25 -0
- data/lib/pg_eventstore/query_strategy.rb +19 -0
- data/lib/pg_eventstore/raw_event.rb +46 -0
- data/lib/pg_eventstore/rspec/test_helpers.rb +21 -8
- data/lib/pg_eventstore/sql_builder.rb +87 -8
- data/lib/pg_eventstore/stream.rb +14 -17
- data/lib/pg_eventstore/stream_global_index.rb +28 -0
- data/lib/pg_eventstore/subscriptions/basic_runner.rb +4 -4
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rb +5 -17
- data/lib/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rb +36 -0
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rb +13 -1
- data/lib/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rb +19 -14
- data/lib/pg_eventstore/subscriptions/events_processor.rb +21 -19
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/multiple.rb +63 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/replica.rb +68 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer/single.rb +62 -0
- data/lib/pg_eventstore/subscriptions/events_processor_consumer.rb +44 -0
- data/lib/pg_eventstore/subscriptions/events_subscription_position_worker.rb +68 -0
- data/lib/pg_eventstore/subscriptions/queries/event_subscription_position_queries.rb +177 -0
- data/lib/pg_eventstore/subscriptions/queries/subscription_command_queries.rb +5 -5
- data/lib/pg_eventstore/subscriptions/queries/subscription_queries.rb +80 -56
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_command_queries.rb +2 -2
- data/lib/pg_eventstore/subscriptions/queries/subscriptions_set_queries.rb +1 -1
- data/lib/pg_eventstore/subscriptions/replica_subscription_handler.rb +140 -0
- data/lib/pg_eventstore/subscriptions/replica_subscription_runner.rb +9 -0
- data/lib/pg_eventstore/subscriptions/subscription.rb +9 -7
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/collection.rb +36 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/index_read_strategy.rb +82 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategies/replication_strategy.rb +75 -0
- data/lib/pg_eventstore/subscriptions/subscription_feed_strategy.rb +31 -0
- data/lib/pg_eventstore/subscriptions/subscription_feeder.rb +26 -2
- data/lib/pg_eventstore/subscriptions/subscription_handler_performance.rb +5 -5
- data/lib/pg_eventstore/subscriptions/subscription_runner.rb +20 -22
- data/lib/pg_eventstore/subscriptions/subscription_runner_commands/reset_position.rb +1 -1
- data/lib/pg_eventstore/subscriptions/subscription_runners_feeder.rb +10 -11
- data/lib/pg_eventstore/subscriptions/subscriptions_lifecycle.rb +0 -12
- data/lib/pg_eventstore/subscriptions/subscriptions_manager.rb +84 -29
- data/lib/pg_eventstore/{subscriptions/synchronized_array.rb → synchronized_array.rb} +15 -0
- data/lib/pg_eventstore/tasks/setup.rake +32 -33
- data/lib/pg_eventstore/utils.rb +39 -0
- data/lib/pg_eventstore/version.rb +1 -1
- data/lib/pg_eventstore/web/application.rb +104 -20
- data/lib/pg_eventstore/web/paginator/base_collection.rb +5 -1
- data/lib/pg_eventstore/web/paginator/event_types_collection.rb +14 -4
- data/lib/pg_eventstore/web/paginator/events_collection.rb +29 -33
- data/lib/pg_eventstore/web/paginator/helpers.rb +19 -12
- data/lib/pg_eventstore/web/paginator/markers_collection.rb +48 -0
- data/lib/pg_eventstore/web/paginator/stream_contexts_collection.rb +13 -2
- data/lib/pg_eventstore/web/paginator/stream_ids_collection.rb +21 -11
- data/lib/pg_eventstore/web/paginator/stream_names_collection.rb +18 -4
- data/lib/pg_eventstore/web/paginator/streams_collection.rb +95 -0
- data/lib/pg_eventstore/web/public/javascripts/pg_eventstore.js +49 -22
- data/lib/pg_eventstore/web/subscriptions/helpers.rb +2 -2
- data/lib/pg_eventstore/web/subscriptions/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/set_collection.rb +1 -1
- data/lib/pg_eventstore/web/subscriptions/with_state/subscriptions.rb +1 -1
- data/lib/pg_eventstore/web/views/home/dashboard.erb +11 -9
- data/lib/pg_eventstore/web/views/home/partials/event_filter.erb +18 -5
- data/lib/pg_eventstore/web/views/home/partials/events.erb +38 -1
- data/lib/pg_eventstore/web/views/home/partials/markers_filter.erb +18 -0
- data/lib/pg_eventstore/web/views/layouts/application.erb +6 -0
- data/lib/pg_eventstore/web/views/streams/index.erb +110 -0
- data/lib/pg_eventstore/web/views/streams/partials/streams.erb +11 -0
- data/lib/pg_eventstore/web/views/subscriptions/index.erb +4 -1
- data/lib/pg_eventstore/web.rb +2 -0
- data/lib/pg_eventstore.rb +26 -63
- data/pg_eventstore.gemspec +6 -4
- data/sig/interfaces/_raw_events_handler.rbs +3 -0
- data/sig/interfaces/subscription_handler.rbs +1 -1
- data/sig/pg/result.rbs +9 -0
- data/sig/pg_eventstore/async_runner.rbs +13 -0
- data/sig/pg_eventstore/basic_config.rbs +9 -0
- data/sig/pg_eventstore/chunks/chunk.rbs +13 -0
- data/sig/pg_eventstore/chunks/read_api_events_index_chunk.rbs +30 -0
- data/sig/pg_eventstore/chunks/replica_events_index_chunk.rbs +11 -0
- data/sig/pg_eventstore/chunks/repository.rbs +22 -0
- data/sig/pg_eventstore/chunks/subscription_checkpoint_chunk.rbs +18 -0
- data/sig/pg_eventstore/chunks/subscription_events_index_chunk.rbs +37 -0
- data/sig/pg_eventstore/client.rbs +41 -43
- data/sig/pg_eventstore/commands/append.rbs +11 -25
- data/sig/pg_eventstore/commands/event_modifiers/prepare_link_event.rbs +9 -12
- data/sig/pg_eventstore/commands/event_modifiers/prepare_regular_event.rbs +5 -4
- data/sig/pg_eventstore/commands/link_to.rbs +6 -11
- data/sig/pg_eventstore/commands/multiple.rbs +1 -1
- data/sig/pg_eventstore/commands/read.rbs +2 -5
- data/sig/pg_eventstore/commands/read_grouped.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams.rbs +7 -0
- data/sig/pg_eventstore/commands/read_streams_paginated.rbs +16 -0
- data/sig/pg_eventstore/commands/regular_stream_read_paginated.rbs +9 -17
- data/sig/pg_eventstore/commands/revision_check/current_revision.rbs +25 -0
- data/sig/pg_eventstore/commands/revision_check/event_type_revisions_comparison.rbs +14 -0
- data/sig/pg_eventstore/commands/revision_check/expected_revision.rbs +67 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_check.rbs +20 -0
- data/sig/pg_eventstore/commands/revision_check/stream_revision_comparison.rbs +9 -0
- data/sig/pg_eventstore/commands/stream_revision.rbs +7 -0
- data/sig/pg_eventstore/commands/system_stream_read_paginated.rbs +9 -14
- data/sig/pg_eventstore/config.rbs +15 -6
- data/sig/pg_eventstore/connection.rbs +11 -18
- data/sig/pg_eventstore/errors.rbs +64 -34
- data/sig/pg_eventstore/event.rbs +20 -6
- data/sig/pg_eventstore/event_deserializer.rbs +5 -10
- data/sig/pg_eventstore/event_global_index.rbs +60 -0
- data/sig/pg_eventstore/event_marker.rbs +9 -0
- data/sig/pg_eventstore/event_marker_index.rbs +12 -0
- data/sig/pg_eventstore/extensions/acts_as_configurable.rbs +29 -0
- data/sig/pg_eventstore/extensions/options_defaults.rbs +7 -0
- data/sig/pg_eventstore/extensions/options_extension.rbs +9 -1
- data/sig/pg_eventstore/feature_marker.rbs +10 -0
- data/sig/pg_eventstore/maintenance.rbs +12 -8
- data/sig/pg_eventstore/middleware/event_trace.rbs +14 -0
- data/sig/pg_eventstore/partition.rbs +2 -4
- data/sig/pg_eventstore/pg_connection.rbs +8 -0
- data/sig/pg_eventstore/queries/event_marker_queries.rbs +21 -0
- data/sig/pg_eventstore/queries/event_queries.rbs +6 -38
- data/sig/pg_eventstore/queries/events_global_index_queries.rbs +37 -0
- data/sig/pg_eventstore/queries/index_filtering_queries.rbs +50 -0
- data/sig/pg_eventstore/queries/links_resolver.rbs +7 -11
- data/sig/pg_eventstore/queries/maintenance_queries.rbs +12 -9
- data/sig/pg_eventstore/queries/partition_queries.rbs +32 -67
- data/sig/pg_eventstore/queries/replica_queries.rbs +31 -0
- data/sig/pg_eventstore/queries/streams_global_index_queries.rbs +39 -0
- data/sig/pg_eventstore/queries/transaction_queries.rbs +4 -2
- data/sig/pg_eventstore/queries.rbs +11 -21
- data/sig/pg_eventstore/query_builders/basic_filtering.rbs +10 -3
- data/sig/pg_eventstore/query_builders/event_markers_filtering.rbs +17 -0
- data/sig/pg_eventstore/query_builders/event_markers_index_filtering.rbs +69 -0
- data/sig/pg_eventstore/query_builders/event_subscription_positions_filtering.rbs +15 -0
- data/sig/pg_eventstore/query_builders/events_filtering_query.rbs +9 -51
- data/sig/pg_eventstore/query_builders/events_global_index_filtering.rbs +68 -0
- data/sig/pg_eventstore/query_builders/filters/collection.rbs +84 -0
- data/sig/pg_eventstore/query_builders/filters/event_type_filter.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/filter_row.rbs +21 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter.rbs +13 -0
- data/sig/pg_eventstore/query_builders/filters/marker_filter_row.rbs +19 -0
- data/sig/pg_eventstore/query_builders/filters/stream_filter.rbs +24 -0
- data/sig/pg_eventstore/query_builders/index_based_events_filtering.rbs +60 -0
- data/sig/pg_eventstore/query_builders/partitions_filtering.rbs +29 -10
- data/sig/pg_eventstore/query_builders/read_cursor/stream_cursor.rbs +47 -0
- data/sig/pg_eventstore/query_builders/streams_global_index_filtering.rbs +27 -0
- data/sig/pg_eventstore/query_builders/subscription_events_filtering.rbs +26 -0
- data/sig/pg_eventstore/query_strategy/async.rbs +17 -0
- data/sig/pg_eventstore/query_strategy/foreground.rbs +11 -0
- data/sig/pg_eventstore/query_strategy.rbs +7 -0
- data/sig/pg_eventstore/raw_event.rbs +20 -0
- data/sig/pg_eventstore/sql_builder.rbs +32 -10
- data/sig/pg_eventstore/stream.rbs +10 -18
- data/sig/pg_eventstore/stream_global_index.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_processor_handlers.rbs +5 -4
- data/sig/pg_eventstore/subscriptions/callback_handlers/events_subscription_position_worker_handlers.rbs +9 -0
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_feeder_handlers.rbs +17 -12
- data/sig/pg_eventstore/subscriptions/callback_handlers/subscription_runner_handlers.rbs +16 -8
- data/sig/pg_eventstore/subscriptions/event_subscription_position_queries.rbs +30 -0
- data/sig/pg_eventstore/subscriptions/events_processor.rbs +12 -5
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/multiple.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/replica.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer/single.rbs +17 -0
- data/sig/pg_eventstore/subscriptions/events_processor_consumer.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/events_subscription_position_worker.rbs +28 -0
- data/sig/pg_eventstore/subscriptions/queries/subscription_queries.rbs +18 -50
- data/sig/pg_eventstore/subscriptions/replica_subscription_handler.rbs +33 -0
- data/sig/pg_eventstore/subscriptions/replica_subscription_runner.rbs +4 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/collection.rbs +14 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/index_read_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy/replication_strategy.rbs +23 -0
- data/sig/pg_eventstore/subscriptions/subscription_feed_strategy.rbs +11 -0
- data/sig/pg_eventstore/subscriptions/subscription_feeder.rbs +13 -10
- data/sig/pg_eventstore/subscriptions/subscription_handler_performance.rbs +1 -1
- data/sig/pg_eventstore/subscriptions/subscription_runner.rbs +13 -5
- data/sig/pg_eventstore/subscriptions/subscription_runners_feeder.rbs +5 -5
- data/sig/pg_eventstore/subscriptions/subscriptions_lifecycle.rbs +4 -6
- data/sig/pg_eventstore/subscriptions/subscriptions_manager.rbs +29 -43
- data/sig/pg_eventstore/synchronized_array.rbs +4 -0
- data/sig/pg_eventstore/utils.rbs +18 -11
- data/sig/pg_eventstore/web/application.rbs +13 -3
- data/sig/pg_eventstore/web/paginator/base_collection.rbs +2 -0
- data/sig/pg_eventstore/web/paginator/event_types_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/events_collection.rbs +11 -11
- data/sig/pg_eventstore/web/paginator/helpers.rbs +6 -15
- data/sig/pg_eventstore/web/paginator/markers_collection.rbs +13 -0
- data/sig/pg_eventstore/web/paginator/stream_contexts_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/stream_names_collection.rbs +4 -0
- data/sig/pg_eventstore/web/paginator/streams_collection.rbs +30 -0
- data/sig/pg_eventstore.rbs +8 -26
- metadata +181 -21
- data/lib/pg_eventstore/commands/all_stream_read_grouped.rb +0 -69
- data/lib/pg_eventstore/commands/regular_stream_read_grouped.rb +0 -31
- data/lib/pg_eventstore/subscriptions/queries/service_queries.rb +0 -73
- data/lib/pg_eventstore/subscriptions/subscription_position_evaluation.rb +0 -195
- data/lib/pg_eventstore/web/views/home/partials/system_stream_filter.erb +0 -15
- data/sig/pg_eventstore/commands/all_stream_read_grouped.rbs +0 -16
- data/sig/pg_eventstore/commands/regular_stream_read_grouped.rbs +0 -8
- data/sig/pg_eventstore/subscriptions/queries/service_queries.rbs +0 -15
- data/sig/pg_eventstore/subscriptions/subscription_position_evaluation.rbs +0 -53
- data/sig/pg_eventstore/subscriptions/synchronized_array.rbs +0 -4
- /data/sig/interfaces/{_raw_event_handler.rbs → raw_event_handler.rbs} +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
CONCURRENCY = ENV['CONCURRENCY']&.to_i || 10
|
|
4
|
+
|
|
5
|
+
PgEventstore.configure(name: :_eventstore_db_connection) do |config|
|
|
6
|
+
config.connection_pool_size = CONCURRENCY * 10
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
partitions = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
10
|
+
conn.exec('select * from partitions where event_type is null')
|
|
11
|
+
end.to_a
|
|
12
|
+
|
|
13
|
+
stream_name_partitions = partitions.reject { _1['stream_name'].nil? }.group_by { _1['context'] }
|
|
14
|
+
stream_name_partitions = stream_name_partitions.to_h do |context, context_parts|
|
|
15
|
+
context_parts = context_parts.to_h { |p| [p['stream_name'], p['id']] }
|
|
16
|
+
[context, context_parts]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
total_streams = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
20
|
+
conn.exec('explain select * from "$streams"')
|
|
21
|
+
end.first['QUERY PLAN'][/rows=\d+/].sub('rows=', '').to_i
|
|
22
|
+
|
|
23
|
+
tables = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
24
|
+
conn.exec('select table_name from partitions where event_type is not null')
|
|
25
|
+
end.to_a.map { _1['table_name'] }
|
|
26
|
+
|
|
27
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
28
|
+
conn.exec('delete from streams_global_index')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
puts "Indexing streams. Approximate number of streams to process: #{total_streams}. Concurrency is #{CONCURRENCY} concurrent writers."
|
|
32
|
+
puts <<~TEXT
|
|
33
|
+
This migration consumes CONCURRENCY x10 connections. Make sure you have plenty of them. Migrations are idempotent, \
|
|
34
|
+
so you can break, adjust settings if needed and then start over.
|
|
35
|
+
TEXT
|
|
36
|
+
puts
|
|
37
|
+
|
|
38
|
+
processed = 0
|
|
39
|
+
processed_was = 0
|
|
40
|
+
time = Time.now
|
|
41
|
+
lock = Thread::Mutex.new
|
|
42
|
+
sub_partitions_count_cache = {}
|
|
43
|
+
threads = CONCURRENCY.times.map do |t|
|
|
44
|
+
Thread.new do
|
|
45
|
+
tables.each do |table|
|
|
46
|
+
global_position = 0
|
|
47
|
+
loop do
|
|
48
|
+
events = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
49
|
+
conn.exec_params(<<~SQL, [global_position, CONCURRENCY, t])
|
|
50
|
+
select context, stream_name, stream_id, global_position
|
|
51
|
+
from "#{table}"
|
|
52
|
+
where global_position > $1 and global_position % $2 = $3 and stream_revision = 0
|
|
53
|
+
group by context, stream_name, stream_id, global_position
|
|
54
|
+
order by global_position asc
|
|
55
|
+
limit 100
|
|
56
|
+
SQL
|
|
57
|
+
end.to_a
|
|
58
|
+
break if events.empty?
|
|
59
|
+
|
|
60
|
+
global_position = events.last['global_position']
|
|
61
|
+
|
|
62
|
+
# retrieve stream revision
|
|
63
|
+
events.each_slice(10) do |sliced_events|
|
|
64
|
+
query_runner = PgEventstore::AsyncRunner.new
|
|
65
|
+
sliced_events.each do |event|
|
|
66
|
+
query_runner.async do
|
|
67
|
+
query_strategy = PgEventstore::QueryStrategy::Async.new(PgEventstore.connection(:_eventstore_db_connection))
|
|
68
|
+
context = event['context']
|
|
69
|
+
stream_name = event['stream_name']
|
|
70
|
+
stream_id = event['stream_id']
|
|
71
|
+
sub_partitions_count_cache[[context, stream_name]] ||= query_strategy.exec_params(
|
|
72
|
+
'select count(*) as c_all from partitions where context = $1 and stream_name = $2',
|
|
73
|
+
[context, stream_name]
|
|
74
|
+
).first['c_all']
|
|
75
|
+
if sub_partitions_count_cache[[context, stream_name]] > 50
|
|
76
|
+
sub_partitions = query_strategy.exec_params(<<~SQL, [context, stream_name]).map { _1['table_name'] }
|
|
77
|
+
select table_name from partitions where context = $1 and stream_name = $2 and event_type is not null
|
|
78
|
+
SQL
|
|
79
|
+
max_revisions = []
|
|
80
|
+
sub_partitions.each_slice(50) do |table_names|
|
|
81
|
+
q_parts = table_names.map do |table_name|
|
|
82
|
+
<<~SQL
|
|
83
|
+
select max(stream_revision) as stream_revision
|
|
84
|
+
from #{table_name}
|
|
85
|
+
where context = $1 and stream_name = $2 and stream_id = $3
|
|
86
|
+
SQL
|
|
87
|
+
end
|
|
88
|
+
q_parts = q_parts.map { "(#{_1})" }.join(' union all ')
|
|
89
|
+
q = "select coalesce(max(stream_revision), -1) as stream_revision from (#{q_parts})"
|
|
90
|
+
max_revisions.push(
|
|
91
|
+
query_strategy.exec_params(q, [context, stream_name, stream_id]).first['stream_revision']
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
event['stream_revision'] = max_revisions.max
|
|
95
|
+
else
|
|
96
|
+
q = <<~SQL
|
|
97
|
+
select max(stream_revision) as stream_revision
|
|
98
|
+
from events
|
|
99
|
+
where context = $1 and stream_name = $2 and stream_id = $3
|
|
100
|
+
SQL
|
|
101
|
+
attrs = query_strategy.exec_params(q, [context, stream_name, stream_id]).to_a.first
|
|
102
|
+
event['stream_revision'] = attrs['stream_revision']
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
query_runner.run
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
values = events.map do |event|
|
|
110
|
+
partition_id = stream_name_partitions[event['context']][event['stream_name']]
|
|
111
|
+
stream_id = PG::Connection.escape(event['stream_id'])
|
|
112
|
+
stream_revision = event['stream_revision']
|
|
113
|
+
starting_position = event['global_position']
|
|
114
|
+
"(#{partition_id}, '#{stream_id}', #{stream_revision}, #{starting_position})"
|
|
115
|
+
end.join(',')
|
|
116
|
+
|
|
117
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
118
|
+
conn.exec(<<~SQL)
|
|
119
|
+
INSERT INTO streams_global_index
|
|
120
|
+
("partition_id", "stream_id", "stream_revision", "starting_position")
|
|
121
|
+
VALUES #{values}
|
|
122
|
+
SQL
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
lock.synchronize do
|
|
126
|
+
processed += events.size
|
|
127
|
+
next if Time.now - time < 2
|
|
128
|
+
|
|
129
|
+
time_was = time
|
|
130
|
+
time = Time.now
|
|
131
|
+
|
|
132
|
+
performance_info = <<~TEXT.strip
|
|
133
|
+
Processed: #{processed}. Left: #{total_streams - processed} (approximately). \
|
|
134
|
+
Performance: #{((processed - processed_was) / (time - time_was)).round(2)} streams/second.
|
|
135
|
+
TEXT
|
|
136
|
+
processed_was = processed
|
|
137
|
+
print "#{performance_info} \r"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
threads.each(&:join)
|
|
144
|
+
|
|
145
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
146
|
+
puts 'Running cluster on streams_global_index. This may take some time.'
|
|
147
|
+
conn.exec('CLUSTER streams_global_index USING idx_streams_global_index_on_starting_position')
|
|
148
|
+
puts 'Running vacuum on streams_global_index. This may take some time.'
|
|
149
|
+
conn.exec('VACUUM (ANALYZE) streams_global_index')
|
|
150
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
CREATE TABLE public.events_global_index
|
|
2
|
+
(
|
|
3
|
+
global_position bigint NOT NULL,
|
|
4
|
+
stream_revision bigint NOT NULL,
|
|
5
|
+
context_partition_id bigint NOT NULL,
|
|
6
|
+
stream_name_partition_id bigint NOT NULL,
|
|
7
|
+
event_type_partition_id bigint NOT NULL,
|
|
8
|
+
streams_global_index_id bigint NOT NULL
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE INDEX idx_events_idx_on_global_position ON public.events_global_index
|
|
12
|
+
USING btree (global_position) INCLUDE (event_type_partition_id);
|
|
13
|
+
|
|
14
|
+
-- (context, global_position)
|
|
15
|
+
CREATE INDEX idx_events_idx_on_ctx_part_id_N_position ON public.events_global_index
|
|
16
|
+
USING btree (context_partition_id, global_position) INCLUDE (event_type_partition_id);
|
|
17
|
+
|
|
18
|
+
-- (context, stream_name, global_position)
|
|
19
|
+
CREATE INDEX idx_events_idx_on_stream_name_part_id_N_position ON public.events_global_index
|
|
20
|
+
USING btree (stream_name_partition_id, global_position) INCLUDE (event_type_partition_id);
|
|
21
|
+
|
|
22
|
+
-- (context, stream_name, event_type, global_position)
|
|
23
|
+
CREATE INDEX idx_events_idx_on_e_type_part_id_N_position ON public.events_global_index
|
|
24
|
+
USING btree (event_type_partition_id, global_position);
|
|
25
|
+
|
|
26
|
+
-- (context, stream_name, stream_id, global_position)
|
|
27
|
+
-- Including stream_revision keeps us from creating another index to cover event markers queries
|
|
28
|
+
CREATE INDEX idx_events_idx_on_streams_idx_id_N_position ON public.events_global_index
|
|
29
|
+
USING btree (streams_global_index_id, global_position) INCLUDE (event_type_partition_id, stream_revision);
|
|
30
|
+
|
|
31
|
+
-- (context, stream_name, stream_id, stream_revision)
|
|
32
|
+
CREATE INDEX idx_events_idx_on_streams_idx_id_N_revision ON public.events_global_index
|
|
33
|
+
USING btree (streams_global_index_id, stream_revision) INCLUDE (event_type_partition_id, global_position);
|
|
34
|
+
|
|
35
|
+
-- (context, stream_name, event_type, stream_id, global_position)
|
|
36
|
+
-- Including stream_revision keeps us from creating another index to cover event markers queries
|
|
37
|
+
CREATE INDEX idx_events_idx_on_streams_idx_id_N_e_type_part_id_n_position ON public.events_global_index
|
|
38
|
+
USING btree (streams_global_index_id, event_type_partition_id, global_position) INCLUDE (stream_revision);
|
|
39
|
+
|
|
40
|
+
-- (context, stream_name, event_type, stream_id, stream_revision)
|
|
41
|
+
CREATE INDEX idx_events_idx_on_streams_idx_id_N_e_type_part_id_n_revision ON public.events_global_index
|
|
42
|
+
USING btree (streams_global_index_id, event_type_partition_id, stream_revision) INCLUDE (global_position);
|
|
43
|
+
|
|
44
|
+
CREATE TABLE public.event_subscription_positions
|
|
45
|
+
(
|
|
46
|
+
global_position bigint NOT NULL,
|
|
47
|
+
subscription_position bigserial NOT NULL
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE public.event_subscription_positions_unprocessed
|
|
51
|
+
(
|
|
52
|
+
global_position bigint NOT NULL
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
CREATE INDEX idx_event_subscription_positions_sposition_N_gposition ON public.event_subscription_positions
|
|
56
|
+
USING btree (subscription_position, global_position);
|
|
57
|
+
|
|
58
|
+
CREATE INDEX idx_event_subscription_positions_gposition_N_sposition ON public.event_subscription_positions
|
|
59
|
+
USING btree (global_position, subscription_position);
|
|
60
|
+
|
|
61
|
+
CREATE INDEX idx_event_subscription_positions_unprocessed_gposition ON public.event_subscription_positions_unprocessed
|
|
62
|
+
USING btree (global_position);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
CONCURRENCY = ENV['CONCURRENCY']&.to_i || 10
|
|
4
|
+
|
|
5
|
+
PgEventstore.configure(name: :_eventstore_db_connection) do |config|
|
|
6
|
+
config.connection_pool_size = CONCURRENCY
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
partitions = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
10
|
+
conn.exec('select * from partitions')
|
|
11
|
+
end.to_a
|
|
12
|
+
context_partitions = partitions.select { _1['stream_name'].nil? }.to_h { [_1['context'], _1['id']] }
|
|
13
|
+
event_type_partitions = partitions.reject { _1['stream_name'].nil? }.group_by { _1['context'] }
|
|
14
|
+
event_type_partitions = event_type_partitions.map do |context, context_parts|
|
|
15
|
+
context_parts = context_parts.group_by { |p| p['stream_name'] }
|
|
16
|
+
context_parts = context_parts.map do |stream_name, parts|
|
|
17
|
+
stream_name_part = parts.find { _1['event_type'].nil? }
|
|
18
|
+
event_type_parts = parts - [stream_name_part]
|
|
19
|
+
event_type_parts = event_type_parts.map do |part|
|
|
20
|
+
[part['event_type'], part]
|
|
21
|
+
end
|
|
22
|
+
[stream_name, { stream_name_part:, event_types: event_type_parts.to_h }]
|
|
23
|
+
end
|
|
24
|
+
[context, context_parts.to_h]
|
|
25
|
+
end.to_h
|
|
26
|
+
|
|
27
|
+
total_events = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
28
|
+
conn.exec('explain select * from events')
|
|
29
|
+
end.first['QUERY PLAN'][/rows=\d+/].sub('rows=', '').to_i
|
|
30
|
+
|
|
31
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
32
|
+
conn.exec('delete from events_global_index')
|
|
33
|
+
conn.exec('delete from event_subscription_positions_unprocessed')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
puts "Indexing events. Events to process: #{total_events} (approximately). Concurrency is #{CONCURRENCY} concurrent writers."
|
|
37
|
+
puts
|
|
38
|
+
processed = 0
|
|
39
|
+
processed_was = 0
|
|
40
|
+
time = Time.now
|
|
41
|
+
lock = Thread::Mutex.new
|
|
42
|
+
threads = CONCURRENCY.times.map do |t|
|
|
43
|
+
Thread.new do
|
|
44
|
+
event_type_partitions.each_value do |stream_name_parts|
|
|
45
|
+
stream_name_parts.each_value do |partitions_info|
|
|
46
|
+
event_type_parts = partitions_info[:event_types]
|
|
47
|
+
stream_name_part = partitions_info[:stream_name_part]
|
|
48
|
+
event_type_parts.each_value do |event_type_part|
|
|
49
|
+
global_position = 0
|
|
50
|
+
loop do
|
|
51
|
+
events = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
52
|
+
conn.exec_params(<<~SQL, [global_position, CONCURRENCY, t])
|
|
53
|
+
select global_position, context, stream_name, type, stream_id, stream_revision
|
|
54
|
+
from #{event_type_part['table_name']}
|
|
55
|
+
where global_position > $1 and global_position % $2 = $3
|
|
56
|
+
order by global_position asc
|
|
57
|
+
limit 1_000
|
|
58
|
+
SQL
|
|
59
|
+
end.to_a
|
|
60
|
+
break if events.empty?
|
|
61
|
+
|
|
62
|
+
global_position = events.last['global_position']
|
|
63
|
+
stream_builders = events.map do |event|
|
|
64
|
+
sql_builder = PgEventstore::SQLBuilder.new.from('streams_global_index')
|
|
65
|
+
sql_builder.select(%( id, #{event['global_position']} as event_global_position ))
|
|
66
|
+
sql_builder.where(
|
|
67
|
+
'stream_id = ? and partition_id = ?',
|
|
68
|
+
event['stream_id'], stream_name_part['id']
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
final_streams_builder = PgEventstore::SQLBuilder.union_builders(stream_builders)
|
|
72
|
+
stream_ids = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
73
|
+
conn.exec_params(*final_streams_builder.to_exec_params)
|
|
74
|
+
end.to_a
|
|
75
|
+
stream_ids = stream_ids.to_h { [_1['event_global_position'], _1['id']] }
|
|
76
|
+
|
|
77
|
+
events_idx_values = []
|
|
78
|
+
global_positions = []
|
|
79
|
+
events.each do |event|
|
|
80
|
+
stream_idx_id = stream_ids[event['global_position']]
|
|
81
|
+
ctx_partition_id = context_partitions[event['context']]
|
|
82
|
+
stream_name_partition_id = stream_name_part['id']
|
|
83
|
+
event_type_partition_id = event_type_part['id']
|
|
84
|
+
events_idx_values << "(#{event['global_position']}, #{ctx_partition_id}, #{stream_name_partition_id}, #{event_type_partition_id}, #{stream_idx_id}, #{event['stream_revision']})"
|
|
85
|
+
global_positions << "(#{event['global_position']})"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
89
|
+
conn.exec(<<~SQL)
|
|
90
|
+
INSERT INTO events_global_index ("global_position", "context_partition_id", "stream_name_partition_id", "event_type_partition_id", "streams_global_index_id", "stream_revision") VALUES #{events_idx_values.join(',')};
|
|
91
|
+
INSERT INTO event_subscription_positions_unprocessed ("global_position") VALUES #{global_positions.join(',')};
|
|
92
|
+
SQL
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
lock.synchronize do
|
|
96
|
+
processed += events.size
|
|
97
|
+
next if Time.now - time < 2
|
|
98
|
+
|
|
99
|
+
time_was = time
|
|
100
|
+
time = Time.now
|
|
101
|
+
|
|
102
|
+
performance_info = <<~TEXT.strip
|
|
103
|
+
Processed: #{processed}. Left: #{total_events - processed}(approximately). \
|
|
104
|
+
Performance: #{((processed - processed_was) / (time - time_was)).round(2)} events/second.
|
|
105
|
+
TEXT
|
|
106
|
+
processed_was = processed
|
|
107
|
+
print "#{performance_info} \r"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
threads.each(&:join)
|
|
116
|
+
|
|
117
|
+
puts
|
|
118
|
+
|
|
119
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
120
|
+
puts 'Running cluster on events_global_index. This may take some time.'
|
|
121
|
+
conn.exec('CLUSTER events_global_index USING idx_events_idx_on_global_position')
|
|
122
|
+
puts 'Running vacuum on events_global_index. This may take some time.'
|
|
123
|
+
conn.exec('VACUUM (ANALYZE) events_global_index')
|
|
124
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
event_subscription_position_queries = PgEventstore::EventSubscriptionPositionQueries.new(
|
|
4
|
+
PgEventstore.connection(:_eventstore_db_connection)
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
total_count = PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
8
|
+
conn.exec('select count(*) as c_all from event_subscription_positions_unprocessed')
|
|
9
|
+
end.first['c_all'] || 0
|
|
10
|
+
processed = 0
|
|
11
|
+
puts "Assigning event subscription positions. Total count: #{total_count} events."
|
|
12
|
+
|
|
13
|
+
loop do
|
|
14
|
+
updated_num = event_subscription_position_queries.assign_subscription_position
|
|
15
|
+
break if updated_num == 0
|
|
16
|
+
|
|
17
|
+
processed += updated_num
|
|
18
|
+
print "Processed: #{processed}. Left: #{total_count - processed} \r"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
puts
|
|
22
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
23
|
+
puts 'Running vacuum on event_subscription_positions_unprocessed. This may take some time.'
|
|
24
|
+
conn.exec('VACUUM (ANALYZE) event_subscription_positions_unprocessed')
|
|
25
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
update subscriptions
|
|
2
|
+
set current_position = (select subscription_position
|
|
3
|
+
from event_subscription_positions
|
|
4
|
+
where global_position <= subscriptions.current_position
|
|
5
|
+
order by global_position desc
|
|
6
|
+
limit 1)
|
|
7
|
+
where current_position is not null;
|
|
8
|
+
|
|
9
|
+
update subscriptions
|
|
10
|
+
set options = jsonb_set(
|
|
11
|
+
options,
|
|
12
|
+
'{from_position}',
|
|
13
|
+
to_jsonb(coalesce((select subscription_position
|
|
14
|
+
from event_subscription_positions
|
|
15
|
+
where global_position <= (subscriptions.options ->> 'from_position')::bigint
|
|
16
|
+
order by global_position desc
|
|
17
|
+
limit 1), 0))
|
|
18
|
+
)
|
|
19
|
+
where options ? 'from_position';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
DROP INDEX idx_partitions_by_event_type;
|
|
2
|
+
|
|
3
|
+
CREATE INDEX idx_partitions_by_event_type_and_id ON public.partitions USING btree (event_type, id);
|
|
4
|
+
CREATE INDEX idx_partitions_by_context_and_stream_name_and_event_type_and_id ON public.partitions
|
|
5
|
+
USING btree (context, stream_name, event_type, id);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ALTER TABLE public.partitions
|
|
2
|
+
ADD COLUMN parent_stream_name_partition_id bigint;
|
|
3
|
+
ALTER TABLE public.partitions
|
|
4
|
+
ADD COLUMN parent_context_partition_id bigint;
|
|
5
|
+
|
|
6
|
+
UPDATE partitions p
|
|
7
|
+
SET parent_context_partition_id = (SELECT id
|
|
8
|
+
FROM partitions
|
|
9
|
+
WHERE context = p.context AND stream_name IS NULL AND event_type IS NULL)
|
|
10
|
+
WHERE stream_name IS NOT NULL;
|
|
11
|
+
|
|
12
|
+
UPDATE partitions p
|
|
13
|
+
SET parent_stream_name_partition_id = (SELECT id
|
|
14
|
+
FROM partitions
|
|
15
|
+
WHERE context = p.context AND stream_name = p.stream_name AND event_type IS NULL)
|
|
16
|
+
WHERE event_type IS NOT NULL;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
puts <<~TEXT
|
|
4
|
+
Changing stream_revision from int to bigint. In order to do so we need to detach each event type partition, change \
|
|
5
|
+
stream_revision column type and attach the partition again to the partent table.
|
|
6
|
+
TEXT
|
|
7
|
+
|
|
8
|
+
filters = PgEventstore::QueryBuilders::Filters::Collection.new
|
|
9
|
+
partition_queries = PgEventstore::PartitionQueries.new(PgEventstore.connection(:_eventstore_db_connection))
|
|
10
|
+
|
|
11
|
+
event_type_partitions = partition_queries.partitions(filters)
|
|
12
|
+
|
|
13
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
14
|
+
event_type_partitions.each do |partition|
|
|
15
|
+
begin
|
|
16
|
+
partition_queries.detach_event_type_partition(partition)
|
|
17
|
+
rescue PG::Error
|
|
18
|
+
# the partition was already detached in previous runs. Just proceed to the next step
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
puts "Starting changing stream_revision from int to bigint for #{partition.event_type.inspect} event type partition."
|
|
22
|
+
conn.exec("ALTER TABLE #{partition.table_name} ALTER COLUMN stream_revision TYPE bigint")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
conn.exec('ALTER TABLE events ALTER COLUMN stream_revision TYPE bigint')
|
|
26
|
+
|
|
27
|
+
event_type_partitions.each do |partition|
|
|
28
|
+
partition_queries.attach_event_type_partition(partition)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
puts 'Running vacuum on events.'
|
|
33
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
34
|
+
conn.exec('VACUUM (ANALYZE) events')
|
|
35
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
CREATE TABLE public.maintenance_tasks
|
|
2
|
+
(
|
|
3
|
+
task_name character varying COLLATE "POSIX" NOT NULL,
|
|
4
|
+
locked_at timestamp without time zone,
|
|
5
|
+
performed_at timestamp without time zone
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
CREATE UNIQUE INDEX idx_maintenance_tasks_task_name ON maintenance_tasks USING btree (task_name);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
CREATE TABLE public.event_markers
|
|
2
|
+
(
|
|
3
|
+
id bigserial NOT NULL,
|
|
4
|
+
name text NOT NULL
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
CREATE UNIQUE INDEX idx_event_markers_on_name ON public.event_markers
|
|
8
|
+
USING btree (name) INCLUDE (id);
|
|
9
|
+
|
|
10
|
+
CREATE INDEX idx_event_markers_on_id ON public.event_markers
|
|
11
|
+
USING btree (id) INCLUDE (name);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE public.event_markers_index
|
|
14
|
+
(
|
|
15
|
+
marker_id bigint NOT NULL,
|
|
16
|
+
streams_global_index_id bigint NOT NULL,
|
|
17
|
+
event_type_partition_id bigint NOT NULL,
|
|
18
|
+
global_position bigint NOT NULL,
|
|
19
|
+
stream_revision bigint NOT NULL
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE INDEX idx_event_markers_index_on_marker_N_stream_N_rev ON public.event_markers_index
|
|
23
|
+
USING btree (marker_id, streams_global_index_id, stream_revision) INCLUDE (global_position, event_type_partition_id);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX idx_event_markers_index_on_marker_N_stream_N_partition_N_rev ON public.event_markers_index
|
|
26
|
+
USING btree (marker_id, streams_global_index_id, event_type_partition_id, stream_revision) INCLUDE (global_position);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX idx_event_markers_index_on_marker_N_pos ON public.event_markers_index
|
|
29
|
+
USING btree (marker_id, global_position) INCLUDE (event_type_partition_id);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX idx_event_markers_index_on_marker_N_partition_N_pos ON public.event_markers_index
|
|
32
|
+
USING btree (marker_id, event_type_partition_id, global_position);
|
|
33
|
+
|
|
34
|
+
CREATE INDEX idx_event_markers_index_on_pos ON public.event_markers_index
|
|
35
|
+
USING btree (global_position);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
PgEventstore.connection(:_eventstore_db_connection).with do |conn|
|
|
4
|
+
conn.transaction do
|
|
5
|
+
conn.exec(<<~SQL)
|
|
6
|
+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
7
|
+
SQL
|
|
8
|
+
conn.exec(<<~SQL)
|
|
9
|
+
CREATE INDEX idx_partitions_context_and_stream_name_search ON public.partitions
|
|
10
|
+
USING GIN ((context || '#{PgEventstore::Event::SYSTEM_SYMBOL}' || stream_name) gin_trgm_ops)
|
|
11
|
+
WHERE stream_name IS NOT NULL AND event_type IS NULL;
|
|
12
|
+
SQL
|
|
13
|
+
conn.exec(<<~SQL)
|
|
14
|
+
CREATE INDEX idx_partitions_context_search ON public.partitions USING GIN (context gin_trgm_ops)
|
|
15
|
+
WHERE stream_name IS NULL and event_type IS NULL;
|
|
16
|
+
CREATE INDEX idx_partitions_event_type_search ON public.partitions USING GIN (event_type gin_trgm_ops)
|
|
17
|
+
WHERE event_type IS NOT NULL;
|
|
18
|
+
|
|
19
|
+
COMMENT ON INDEX idx_partitions_context_search IS 'Admin web UI search support.';
|
|
20
|
+
COMMENT ON INDEX idx_partitions_context_and_stream_name_search IS 'Admin web UI search support.';
|
|
21
|
+
COMMENT ON INDEX idx_partitions_event_type_search IS 'Admin web UI search support.';
|
|
22
|
+
SQL
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE public.events ALTER COLUMN id DROP DEFAULT;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
CREATE FUNCTION public.create_context_partition_table()
|
|
2
|
+
RETURNS trigger
|
|
3
|
+
LANGUAGE plpgsql
|
|
4
|
+
AS $$
|
|
5
|
+
BEGIN
|
|
6
|
+
EXECUTE format(
|
|
7
|
+
'CREATE TABLE public.%I PARTITION OF public.events FOR VALUES IN (%L) PARTITION BY LIST (stream_name)',
|
|
8
|
+
NEW.table_name,
|
|
9
|
+
NEW.context
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
EXECUTE format(
|
|
13
|
+
'COMMENT ON TABLE public.%I IS %L',
|
|
14
|
+
NEW.table_name,
|
|
15
|
+
format('''%s'' context partition', NEW.context)
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
RETURN NEW;
|
|
19
|
+
END;
|
|
20
|
+
$$;
|
|
21
|
+
|
|
22
|
+
CREATE FUNCTION public.create_stream_name_partition_table()
|
|
23
|
+
RETURNS trigger
|
|
24
|
+
LANGUAGE plpgsql
|
|
25
|
+
AS $$
|
|
26
|
+
DECLARE
|
|
27
|
+
context_partition_name public.partitions.table_name%TYPE;
|
|
28
|
+
BEGIN
|
|
29
|
+
SELECT table_name
|
|
30
|
+
INTO STRICT context_partition_name
|
|
31
|
+
FROM public.partitions
|
|
32
|
+
WHERE id = NEW.parent_context_partition_id;
|
|
33
|
+
|
|
34
|
+
EXECUTE format(
|
|
35
|
+
'CREATE TABLE public.%I PARTITION OF public.%I FOR VALUES IN (%L) PARTITION BY LIST (type)',
|
|
36
|
+
NEW.table_name,
|
|
37
|
+
context_partition_name,
|
|
38
|
+
NEW.stream_name
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
EXECUTE format(
|
|
42
|
+
'COMMENT ON TABLE public.%I IS %L',
|
|
43
|
+
NEW.table_name,
|
|
44
|
+
format('''%s'' context and ''%s'' stream name partition', NEW.context, NEW.stream_name)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
RETURN NEW;
|
|
48
|
+
END;
|
|
49
|
+
$$;
|
|
50
|
+
|
|
51
|
+
CREATE FUNCTION public.create_event_type_partition_table()
|
|
52
|
+
RETURNS trigger
|
|
53
|
+
LANGUAGE plpgsql
|
|
54
|
+
AS $$
|
|
55
|
+
DECLARE
|
|
56
|
+
stream_name_partition_name public.partitions.table_name%TYPE;
|
|
57
|
+
BEGIN
|
|
58
|
+
SELECT table_name
|
|
59
|
+
INTO STRICT stream_name_partition_name
|
|
60
|
+
FROM public.partitions
|
|
61
|
+
WHERE id = NEW.parent_stream_name_partition_id;
|
|
62
|
+
|
|
63
|
+
EXECUTE format(
|
|
64
|
+
'CREATE TABLE public.%I PARTITION OF public.%I FOR VALUES IN (%L)',
|
|
65
|
+
NEW.table_name,
|
|
66
|
+
stream_name_partition_name,
|
|
67
|
+
NEW.event_type
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
EXECUTE format(
|
|
71
|
+
'COMMENT ON TABLE public.%I IS %L',
|
|
72
|
+
NEW.table_name,
|
|
73
|
+
format(
|
|
74
|
+
'''%s'' context and ''%s'' stream name and ''%s'' event type partition',
|
|
75
|
+
NEW.context,
|
|
76
|
+
NEW.stream_name,
|
|
77
|
+
NEW.event_type
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
RETURN NEW;
|
|
82
|
+
END;
|
|
83
|
+
$$;
|
|
84
|
+
|
|
85
|
+
CREATE TRIGGER create_context_partition_table
|
|
86
|
+
AFTER INSERT ON public.partitions
|
|
87
|
+
FOR EACH ROW
|
|
88
|
+
WHEN (NEW.stream_name IS NULL AND NEW.event_type IS NULL)
|
|
89
|
+
EXECUTE FUNCTION public.create_context_partition_table();
|
|
90
|
+
|
|
91
|
+
CREATE TRIGGER create_stream_name_partition_table
|
|
92
|
+
AFTER INSERT ON public.partitions
|
|
93
|
+
FOR EACH ROW
|
|
94
|
+
WHEN (NEW.stream_name IS NOT NULL AND NEW.event_type IS NULL)
|
|
95
|
+
EXECUTE FUNCTION public.create_stream_name_partition_table();
|
|
96
|
+
|
|
97
|
+
CREATE TRIGGER create_event_type_partition_table
|
|
98
|
+
AFTER INSERT ON public.partitions
|
|
99
|
+
FOR EACH ROW
|
|
100
|
+
WHEN (NEW.event_type IS NOT NULL)
|
|
101
|
+
EXECUTE FUNCTION public.create_event_type_partition_table();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
CREATE UNLOGGED TABLE events_horizon
|
|
2
|
+
(
|
|
3
|
+
global_position bigint not null,
|
|
4
|
+
xact_id xid8 not null default pg_current_xact_id()
|
|
5
|
+
);
|
|
6
|
+
CREATE INDEX idx_xact_id_and_created_at_and_global_position ON events_horizon USING btree(xact_id, global_position);
|
|
7
|
+
COMMENT ON TABLE events_horizon IS 'Internal use only. Data is limited to the PostgreSQL cluster in which it was created. DO NOT INCLUDE ITS DATA INTO YOUR DUMP.';
|
|
8
|
+
|
|
9
|
+
CREATE OR REPLACE FUNCTION log_events_horizon()
|
|
10
|
+
RETURNS TRIGGER AS $$
|
|
11
|
+
BEGIN
|
|
12
|
+
INSERT INTO events_horizon(global_position)
|
|
13
|
+
VALUES (NEW.global_position);
|
|
14
|
+
RETURN NEW;
|
|
15
|
+
END;
|
|
16
|
+
$$ LANGUAGE plpgsql;
|
|
17
|
+
|
|
18
|
+
CREATE TRIGGER log_events_horizon
|
|
19
|
+
AFTER INSERT ON events
|
|
20
|
+
FOR EACH ROW
|
|
21
|
+
EXECUTE FUNCTION log_events_horizon();
|