pg_online_schema_change 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6580f86cf1fc33883f10391990817fb8c885b03eb4ecd1cd3095d46fc2a6bff5
4
- data.tar.gz: 28b702f57765278ed7cdf9f7590c2bbf957d2debe8ace180bacd2a3f2fad98e3
3
+ metadata.gz: 3d69a5ecadf6f0c3b3c27bb2e16e163cfbc6526c4c83b5cbdf4ebef73be62cf9
4
+ data.tar.gz: 5a8ac6b5491692d4680f40637550392ebe5e8a206e7e3b1729967a379231ee8a
5
5
  SHA512:
6
- metadata.gz: b761947d35092a7479589ef2b1bc4f79290e5172d83e1f24bd23af37e4ecdfaf7e26a0d0b91dafed3ad68b6e3012dfcd9ff8f54c861f1270037e9582e1f9db7b
7
- data.tar.gz: a4f8f44660858b0e3fb5d74847e8f4e46e46b5d5237cbea669dcb9880dd3cb6deae9c5b598120169769e57cdb07e67f72cfc0edd6d72ef8c46d8bc9f5284ded6
6
+ metadata.gz: 5b8960dae33e3cf5bace38cb45cacaa555d16433b15703ffda2f2338b5076e716c23271d5f08d77f033cfbe9c6f2ea450e764a8ce934bb3ec9bfd9327cf89735
7
+ data.tar.gz: f003a55abb25ad2bcecf5a4e3b2358bfac4b3c0c55c401f7500a8d92e2b5bd30ebb4891d934cec52a1449e65a4fd9d177a9f87a2493d72b3f949ef47493943e8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.2.0] - 2022-02-17
2
+
3
+ - Use ISOLATION LEVEL SERIALIZABLE ([#42](https://github.com/shayonj/pg-online-schema-change/pull/42)) (props to @jfrost)
4
+
1
5
  ## [0.1.0] - 2022-02-16
2
6
 
3
7
  Initial release
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # pg-online-schema-change / pg-osc
2
2
  [![CircleCI](https://circleci.com/gh/shayonj/pg-online-schema-change/tree/main.svg?style=shield)](https://circleci.com/gh/shayonj/pg-online-schema-change/tree/main)
3
+ [![Gem Version](https://badge.fury.io/rb/pg_online_schema_change.svg)](https://badge.fury.io/rb/pg_online_schema_change)
3
4
 
4
5
  pg-online-schema-change (`pg-osc`) is a tool for making schema changes (any `ALTER` statements) in Postgres tables with minimal locks, thus helping achieve zero downtime schema changes against production workloads.
5
6
 
6
- `pg-osc` uses the concept of shadow table to perform schema changes. At a high level, it copies the contents from a primary table to a shadow table, performs the schema change on the shadow table and swaps the table names in the end while preserving all changes to the primary table using triggers (via audit table).
7
+ `pg-osc` uses the concept of shadow table to perform schema changes. At a high level, it creates a shadow table that looks structurally the same as the primary table, performs the schema change on the shadow table, copies contents from the primary table to the shadow table and swaps the table names in the end while preserving all changes to the primary table using triggers (via audit table).
7
8
 
8
9
  `pg-osc` is inspired by the design and workings of tools like `pg_repack` and `pt-online-schema-change` (MySQL). Read more below on [how does it work](#how-does-it-work), [prominent features](#prominent-features), the [caveats](#caveats) and [examples](#examples)
9
10
 
@@ -33,6 +34,8 @@ Or install it yourself as:
33
34
  ## Usage
34
35
 
35
36
  ```
37
+ pg-online-schema-change help perform
38
+
36
39
  Usage:
37
40
  pg-online-schema-change perform -a, --alter-statement=ALTER_STATEMENT -d, --dbname=DBNAME -h, --host=HOST -p, --port=N -s, --schema=SCHEMA -u, --username=USERNAME -w, --password=PASSWORD
38
41
 
@@ -37,10 +37,10 @@ module PgOnlineSchemaChange
37
37
 
38
38
  setup_audit_table!
39
39
  setup_trigger!
40
- setup_shadow_table!
41
- disable_vacuum!
42
- run_alter_statement!
43
- copy_data!
40
+ setup_shadow_table! # re-uses transaction with serializable
41
+ disable_vacuum! # re-uses transaction with serializable
42
+ run_alter_statement! # re-uses transaction with serializable
43
+ copy_data! # re-uses transaction with serializable
44
44
  run_analyze!
45
45
  replay_and_swap!
46
46
  run_analyze!
@@ -132,17 +132,27 @@ module PgOnlineSchemaChange
132
132
  end
133
133
 
134
134
  def setup_shadow_table!
135
+ # re-uses transaction with serializable
136
+ # This ensures that all queries from here till copy_data run with serializable.
137
+ # This is to to ensure that once the trigger is added to the primay table
138
+ # and contents being copied into the shadow, after a delete all on audit table,
139
+ # any replaying of rows that happen next from audit table do not contain
140
+ # any duplicates. We are ensuring there are no race conditions between
141
+ # adding the trigger, till the copy ends, since they all happen in the
142
+ # same serializable transaction.
143
+ Query.run(client.connection, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", true)
135
144
  logger.info("Setting up shadow table", { shadow_table: shadow_table })
136
145
 
137
- Query.run(client.connection, "SELECT create_table_all('#{client.table}', '#{shadow_table}');")
146
+ Query.run(client.connection, "SELECT create_table_all('#{client.table}', '#{shadow_table}');", true)
138
147
 
139
148
  # update serials
140
- Query.run(client.connection, "SELECT fix_serial_sequence('#{client.table}', '#{shadow_table}');")
149
+ Query.run(client.connection, "SELECT fix_serial_sequence('#{client.table}', '#{shadow_table}');", true)
141
150
  end
142
151
 
143
- # Disabling vacuum to avoid any issues during the process
144
152
  def disable_vacuum!
145
- result = Query.storage_parameters_for(client, client.table) || ""
153
+ # re-uses transaction with serializable
154
+ # Disabling vacuum to avoid any issues during the process
155
+ result = Query.storage_parameters_for(client, client.table, true) || ""
146
156
  primary_table_storage_parameters = Store.set(:primary_table_storage_parameters, result)
147
157
 
148
158
  logger.debug("Disabling vacuum on shadow and audit table",
@@ -156,32 +166,39 @@ module PgOnlineSchemaChange
156
166
  autovacuum_enabled = false, toast.autovacuum_enabled = false
157
167
  );
158
168
  SQL
159
- Query.run(client.connection, sql)
169
+ Query.run(client.connection, sql, true)
160
170
  end
161
171
 
162
172
  def run_alter_statement!
173
+ # re-uses transaction with serializable
163
174
  statement = Query.alter_statement_for(client, shadow_table)
164
175
  logger.info("Running alter statement on shadow table",
165
176
  { shadow_table: shadow_table, parent_table: client.table })
166
- Query.run(client.connection, statement)
177
+ Query.run(client.connection, statement, true)
167
178
 
168
179
  Store.set(:dropped_columns_list, Query.dropped_columns(client))
169
180
  Store.set(:renamed_columns_list, Query.renamed_columns(client))
170
181
  end
171
182
 
172
- # Begin the process to copy data into copy table
173
- # depending on the size of the table, this can be a time
174
- # taking operation.
175
183
  def copy_data!
176
- logger.info("Copying contents..", { shadow_table: shadow_table, parent_table: client.table })
184
+ # re-uses transaction with serializable
185
+ # Begin the process to copy data into copy table
186
+ # depending on the size of the table, this can be a time
187
+ # taking operation.
188
+ logger.info("Clearing contents of audit table before copy..",
189
+ { shadow_table: shadow_table, parent_table: client.table })
190
+ Query.run(client.connection, "DELETE FROM #{audit_table}", true)
177
191
 
192
+ logger.info("Copying contents..", { shadow_table: shadow_table, parent_table: client.table })
178
193
  if client.copy_statement
179
194
  query = format(client.copy_statement, shadow_table: shadow_table)
180
- return Query.run(client.connection, query)
195
+ return Query.run(client.connection, query, true)
181
196
  end
182
197
 
183
198
  sql = Query.copy_data_statement(client, shadow_table)
184
- Query.run(client.connection, sql)
199
+ Query.run(client.connection, sql, true)
200
+ ensure
201
+ Query.run(client.connection, "COMMIT;") # commit the serializable transaction
185
202
  end
186
203
 
187
204
  def replay_and_swap!
@@ -60,7 +60,7 @@ module PgOnlineSchemaChange
60
60
  result
61
61
  end
62
62
 
63
- def table_columns(client, table = nil)
63
+ def table_columns(client, table = nil, reuse_trasaction = false)
64
64
  sql = <<~SQL
65
65
  SELECT attname as column_name, format_type(atttypid, atttypmod) as type, attnum as column_position FROM pg_attribute
66
66
  WHERE attrelid = \'#{table || client.table}\'::regclass AND attnum > 0 AND NOT attisdropped
@@ -68,7 +68,7 @@ module PgOnlineSchemaChange
68
68
  SQL
69
69
  mapped_columns = []
70
70
 
71
- run(client.connection, sql) do |result|
71
+ run(client.connection, sql, reuse_trasaction) do |result|
72
72
  mapped_columns = result.map do |row|
73
73
  row["column_name_regular"] = row["column_name"]
74
74
  row["column_name"] = client.connection.quote_ident(row["column_name"])
@@ -210,13 +210,13 @@ module PgOnlineSchemaChange
210
210
  columns.first
211
211
  end
212
212
 
213
- def storage_parameters_for(client, table)
213
+ def storage_parameters_for(client, table, reuse_trasaction = false)
214
214
  query = <<~SQL
215
215
  SELECT array_to_string(reloptions, ',') as params FROM pg_class WHERE relname=\'#{table}\';
216
216
  SQL
217
217
 
218
218
  columns = []
219
- run(client.connection, query) do |result|
219
+ run(client.connection, query, reuse_trasaction) do |result|
220
220
  columns = result.map { |row| row["params"] }
221
221
  end
222
222
 
@@ -266,8 +266,8 @@ module PgOnlineSchemaChange
266
266
  run(client.connection, query, true)
267
267
  end
268
268
 
269
- def copy_data_statement(client, shadow_table)
270
- select_columns = table_columns(client).map do |entry|
269
+ def copy_data_statement(client, shadow_table, reuse_trasaction = false)
270
+ select_columns = table_columns(client, client.table, reuse_trasaction).map do |entry|
271
271
  entry["column_name_regular"]
272
272
  end
273
273
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgOnlineSchemaChange
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_online_schema_change
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shayon Mukherjee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-16 00:00:00.000000000 Z
11
+ date: 2022-02-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: pg-online-schema-change (pg-osc) is a tool for making schema changes
14
14
  (any ALTER statements) in Postgres tables with minimal locks, thus helping achieve