Current section

27 Versions

Jump to

Compare versions

7 files changed
+139 additions
-48 deletions
  @@ -1,3 +1,11 @@
1 + ## [0.13.0] - 2024-06-27
2 +
3 + **New migration patches:** 9
4 +
5 + ### Fixed
6 +
7 + - Fix `set_transaction_id` trigger not using the PK index on `transactions` due to being dependent on `CURRVAL` for every row. Replaced with a CTE the `EXIST` query is now an index-only scan as it was intended to be. As a consequence, scalability of inserts into the `transactions` table has been greatly improved.
8 +
1 9 ## [0.12.1] - 2024-05-21
2 10
3 11 ### Fixed
  @@ -93,7 +93,7 @@ Due to its use of [`pg_current_xact_id`](https://www.postgresql.org/docs/13/func
93 93 # mix.exs
94 94 def deps do
95 95 [
96 - {:carbonite, "~> 0.12.1"}
96 + {:carbonite, "~> 0.13.0"}
97 97 ]
98 98 end
99 99 ```
  @@ -120,7 +120,7 @@ defmodule MyApp.Repo.Migrations.InstallCarbonite do
120 120 use Ecto.Migration
121 121
122 122 def up do
123 - Carbonite.Migrations.up(1..8)
123 + Carbonite.Migrations.up(1..9)
124 124
125 125 # For each table that you want to capture changes of, you need to install the trigger.
126 126 Carbonite.Migrations.create_trigger(:rabbits)
  @@ -140,7 +140,7 @@ defmodule MyApp.Repo.Migrations.InstallCarbonite do
140 140 Carbonite.Migrations.drop_trigger(:rabbits)
141 141
142 142 # Drop the Carbonite tables.
143 - Carbonite.Migrations.down(8..1)
143 + Carbonite.Migrations.down(9..1)
144 144 end
145 145 end
146 146 ```
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"github">>,<<"https://github.com/bitcrowd/carbonite">>}]}.
2 2 {<<"name">>,<<"carbonite">>}.
3 - {<<"version">>,<<"0.12.1">>}.
3 + {<<"version">>,<<"0.13.0">>}.
4 4 {<<"description">>,<<"Audit trails for Elixir/PostgreSQL based on triggers">>}.
5 5 {<<"elixir">>,<<"~> 1.11">>}.
6 6 {<<"app">>,<<"carbonite">>}.
  @@ -22,19 +22,20 @@
22 22 {<<"requirement">>,<<"~> 0.15 and >= 0.15.11">>},
23 23 {<<"repository">>,<<"hexpm">>}]]}.
24 24 {<<"files">>,
25 - [<<"lib">>,<<"lib/carbonite">>,<<"lib/carbonite/trigger.ex">>,
26 - <<"lib/carbonite/schema.ex">>,<<"lib/carbonite/prefix.ex">>,
27 - <<"lib/carbonite/change.ex">>,<<"lib/carbonite/migrations">>,
28 - <<"lib/carbonite/migrations/helper.ex">>,
29 - <<"lib/carbonite/migrations/v3.ex">>,<<"lib/carbonite/migrations/v1.ex">>,
30 - <<"lib/carbonite/migrations/v7.ex">>,<<"lib/carbonite/migrations/v2.ex">>,
31 - <<"lib/carbonite/migrations/v6.ex">>,
25 + [<<"lib">>,<<"lib/carbonite">>,<<"lib/carbonite/migrations">>,
32 26 <<"lib/carbonite/migrations/version.ex">>,
33 - <<"lib/carbonite/migrations/v8.ex">>,<<"lib/carbonite/migrations/v5.ex">>,
34 - <<"lib/carbonite/migrations/v4.ex">>,<<"lib/carbonite/query.ex">>,
35 - <<"lib/carbonite/outbox.ex">>,<<"lib/carbonite/migrations.ex">>,
36 - <<"lib/carbonite/transaction.ex">>,<<"lib/carbonite/multi.ex">>,
37 - <<"lib/carbonite.ex">>,<<"lib/mix">>,<<"lib/mix/tasks">>,
38 - <<"lib/mix/tasks/carbonite.gen.initial_migration.ex">>,<<".formatter.exs">>,
39 - <<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,<<"CHANGELOG.md">>]}.
27 + <<"lib/carbonite/migrations/v5.ex">>,<<"lib/carbonite/migrations/v2.ex">>,
28 + <<"lib/carbonite/migrations/v3.ex">>,<<"lib/carbonite/migrations/v6.ex">>,
29 + <<"lib/carbonite/migrations/helper.ex">>,
30 + <<"lib/carbonite/migrations/v7.ex">>,<<"lib/carbonite/migrations/v4.ex">>,
31 + <<"lib/carbonite/migrations/v9.ex">>,<<"lib/carbonite/migrations/v1.ex">>,
32 + <<"lib/carbonite/migrations/v8.ex">>,<<"lib/carbonite/change.ex">>,
33 + <<"lib/carbonite/schema.ex">>,<<"lib/carbonite/outbox.ex">>,
34 + <<"lib/carbonite/multi.ex">>,<<"lib/carbonite/transaction.ex">>,
35 + <<"lib/carbonite/prefix.ex">>,<<"lib/carbonite/query.ex">>,
36 + <<"lib/carbonite/trigger.ex">>,<<"lib/carbonite/migrations.ex">>,
37 + <<"lib/mix">>,<<"lib/mix/tasks">>,
38 + <<"lib/mix/tasks/carbonite.gen.initial_migration.ex">>,
39 + <<"lib/carbonite.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,
40 + <<"LICENSE">>,<<"CHANGELOG.md">>]}.
40 41 {<<"build_tools">>,[<<"mix">>]}.
  @@ -18,7 +18,7 @@ defmodule Carbonite.Migrations do
18 18 # --------------------------------- patch levels ---------------------------------
19 19
20 20 @initial_patch 1
21 - @current_patch 8
21 + @current_patch 9
22 22
23 23 @doc false
24 24 @spec initial_patch :: non_neg_integer()
  @@ -125,6 +125,40 @@ defmodule Carbonite.Migrations.V4 do
125 125 :ok
126 126 end
127 127
128 + @spec create_set_transaction_id_procedure(prefix()) :: :ok
129 + def create_set_transaction_id_procedure(prefix) do
130 + """
131 + CREATE OR REPLACE FUNCTION #{prefix}.set_transaction_id() RETURNS TRIGGER AS
132 + $body$
133 + BEGIN
134 + BEGIN
135 + /* verify that no previous INSERT within current transaction (with same id) */
136 + IF
137 + EXISTS(
138 + SELECT 1 FROM #{prefix}.transactions
139 + WHERE id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq'))
140 + AND xact_id = COALESCE(NEW.xact_id, pg_current_xact_id())
141 + )
142 + THEN
143 + NEW.id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq'));
144 + END IF;
145 + EXCEPTION WHEN object_not_in_prerequisite_state THEN
146 + /* when NEXTVAL has never been called within session, we're good */
147 + END;
148 +
149 + NEW.id = COALESCE(NEW.id, NEXTVAL('#{prefix}.transactions_id_seq'));
150 + NEW.xact_id = COALESCE(NEW.xact_id, pg_current_xact_id());
151 +
152 + RETURN NEW;
153 + END
154 + $body$
155 + LANGUAGE plpgsql;
156 + """
157 + |> squish_and_execute()
158 +
159 + :ok
160 + end
161 +
128 162 @impl true
129 163 @spec up([up_option()]) :: :ok
130 164 def up(opts) do
  @@ -161,34 +195,7 @@ defmodule Carbonite.Migrations.V4 do
161 195 """
162 196 |> squish_and_execute()
163 197
164 - """
165 - CREATE OR REPLACE FUNCTION #{prefix}.set_transaction_id() RETURNS TRIGGER AS
166 - $body$
167 - BEGIN
168 - BEGIN
169 - /* verify that no previous INSERT within current transaction (with same id) */
170 - IF
171 - EXISTS(
172 - SELECT 1 FROM #{prefix}.transactions
173 - WHERE id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq'))
174 - AND xact_id = COALESCE(NEW.xact_id, pg_current_xact_id())
175 - )
176 - THEN
177 - NEW.id = COALESCE(NEW.id, CURRVAL('#{prefix}.transactions_id_seq'));
178 - END IF;
179 - EXCEPTION WHEN object_not_in_prerequisite_state THEN
180 - /* when NEXTVAL has never been called within session, we're good */
181 - END;
182 -
183 - NEW.id = COALESCE(NEW.id, NEXTVAL('#{prefix}.transactions_id_seq'));
184 - NEW.xact_id = COALESCE(NEW.xact_id, pg_current_xact_id());
185 -
186 - RETURN NEW;
187 - END
188 - $body$
189 - LANGUAGE plpgsql;
190 - """
191 - |> squish_and_execute()
198 + create_set_transaction_id_procedure(prefix)
192 199
193 200 # ------------- override_xact_id -------------
Loading more files…