logidze 0.12.0 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -5
  3. data/LICENSE.txt +1 -1
  4. data/README.md +263 -103
  5. data/lib/generators/logidze/fx_helper.rb +17 -0
  6. data/lib/generators/logidze/inject_sql.rb +18 -0
  7. data/lib/generators/logidze/install/USAGE +6 -1
  8. data/lib/generators/logidze/install/functions/logidze_compact_history.sql +38 -0
  9. data/lib/generators/logidze/install/functions/logidze_filter_keys.sql +27 -0
  10. data/lib/generators/logidze/install/functions/logidze_logger.sql +150 -0
  11. data/lib/generators/logidze/install/functions/logidze_snapshot.sql +24 -0
  12. data/lib/generators/logidze/install/functions/logidze_version.sql +20 -0
  13. data/lib/generators/logidze/install/install_generator.rb +58 -1
  14. data/lib/generators/logidze/install/templates/hstore.rb.erb +1 -1
  15. data/lib/generators/logidze/install/templates/migration.rb.erb +19 -232
  16. data/lib/generators/logidze/install/templates/migration_fx.rb.erb +41 -0
  17. data/lib/generators/logidze/model/model_generator.rb +49 -13
  18. data/lib/generators/logidze/model/templates/migration.rb.erb +57 -36
  19. data/lib/generators/logidze/model/triggers/logidze.sql +6 -0
  20. data/lib/logidze.rb +27 -14
  21. data/lib/logidze/history.rb +1 -10
  22. data/lib/logidze/ignore_log_data.rb +1 -4
  23. data/lib/logidze/model.rb +48 -35
  24. data/lib/logidze/version.rb +1 -1
  25. metadata +48 -73
  26. data/.gitattributes +0 -3
  27. data/.github/ISSUE_TEMPLATE.md +0 -20
  28. data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
  29. data/.gitignore +0 -40
  30. data/.rubocop.yml +0 -55
  31. data/.travis.yml +0 -46
  32. data/Gemfile +0 -15
  33. data/Rakefile +0 -28
  34. data/assets/pg_log_data_chart.png +0 -0
  35. data/bench/performance/README.md +0 -109
  36. data/bench/performance/diff_bench.rb +0 -38
  37. data/bench/performance/insert_bench.rb +0 -22
  38. data/bench/performance/memory_profile.rb +0 -56
  39. data/bench/performance/setup.rb +0 -315
  40. data/bench/performance/update_bench.rb +0 -38
  41. data/bench/triggers/Makefile +0 -56
  42. data/bench/triggers/Readme.md +0 -58
  43. data/bench/triggers/bench.sql +0 -6
  44. data/bench/triggers/hstore_trigger_setup.sql +0 -38
  45. data/bench/triggers/jsonb_minus_2_setup.sql +0 -47
  46. data/bench/triggers/jsonb_minus_setup.sql +0 -49
  47. data/bench/triggers/keys2_trigger_setup.sql +0 -44
  48. data/bench/triggers/keys_trigger_setup.sql +0 -50
  49. data/bin/console +0 -8
  50. data/bin/setup +0 -9
  51. data/gemfiles/rails42.gemfile +0 -6
  52. data/gemfiles/rails5.gemfile +0 -6
  53. data/gemfiles/rails52.gemfile +0 -6
  54. data/gemfiles/rails6.gemfile +0 -6
  55. data/gemfiles/railsmaster.gemfile +0 -7
  56. data/lib/logidze/ignore_log_data/ignored_columns.rb +0 -46
  57. data/lib/logidze/migration.rb +0 -20
  58. data/logidze.gemspec +0 -41
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "benchmark/ips"
4
- require "./setup"
5
-
6
- params = {
7
- age: Faker::Number.number(2),
8
- email: Faker::Internet.email
9
- }
10
-
11
- params2 = {
12
- email: Faker::Internet.email,
13
- position: Faker::Number.number(3),
14
- name: Faker::Name.name,
15
- age: Faker::Number.number(2),
16
- bio: Faker::Lorem.paragraph
17
- }
18
-
19
- LogidzeBench.cleanup
20
- LogidzeBench.populate
21
-
22
- Benchmark.ips do |x|
23
- x.report("PT UPDATE #1") do
24
- User.random.update!(params)
25
- end
26
-
27
- x.report("Logidze UPDATE #1") do
28
- LogidzeUser.random.update!(params)
29
- end
30
-
31
- x.report("PT UPDATE #2") do
32
- User.random.update!(params2)
33
- end
34
-
35
- x.report("Logidze UPDATE #2") do
36
- LogidzeUser.random.update!(params2)
37
- end
38
- end
@@ -1,56 +0,0 @@
1
- # Database name
2
- ifndef DB
3
- DB = logidze_bench
4
- endif
5
-
6
- # Transactions count
7
- ifndef T
8
- T = 10000
9
- endif
10
-
11
- all: plain hstore jsonb jsonb2 keys keys2
12
-
13
- setup:
14
- createdb $(DB) -w
15
- psql -q -d $(DB) -c 'CREATE EXTENSION IF NOT EXISTS hstore;'
16
-
17
- plain:
18
- $(info )
19
- $(info ====== [START] Update without triggers ======)
20
- pgbench -i -q $(DB)
21
- pgbench -f bench.sql -t $(T) -r $(DB)
22
-
23
- hstore:
24
- $(info )
25
- $(info ====== [START] Update with hstore-based triggers ======)
26
- pgbench -i -q $(DB)
27
- psql -q -d $(DB) -f hstore_trigger_setup.sql
28
- pgbench -f bench.sql -t $(T) -r $(DB)
29
-
30
- jsonb:
31
- $(info )
32
- $(info ====== [START] Update with jsonb-minus triggers ======)
33
- pgbench -i -q $(DB)
34
- psql -q -d $(DB) -f jsonb_minus_setup.sql
35
- pgbench -f bench.sql -t $(T) -r $(DB)
36
-
37
- jsonb2:
38
- $(info )
39
- $(info ====== [START] Update with jsonb-minus triggers ======)
40
- pgbench -i -q $(DB)
41
- psql -q -d $(DB) -f jsonb_minus_2_setup.sql
42
- pgbench -f bench.sql -t $(T) -r $(DB)
43
-
44
- keys:
45
- $(info )
46
- $(info ====== [START] Update with loop thru keys triggers (v1) ======)
47
- pgbench -i -q $(DB)
48
- psql -q -d $(DB) -f keys_trigger_setup.sql
49
- pgbench -f bench.sql -t $(T) -r $(DB)
50
-
51
- keys2:
52
- $(info )
53
- $(info ====== [START] Update with loop thru keys triggers (v2) ======)
54
- pgbench -i -q $(DB)
55
- psql -q -d $(DB) -f keys2_trigger_setup.sql
56
- pgbench -f bench.sql -t $(T) -r $(DB)
@@ -1,58 +0,0 @@
1
- # Triggers benchmarks
2
-
3
- This benchmark uses standard _pg\_bench_ table `pgbench_accounts`.
4
- We consider several approaches for calculating records diff: one uses _hstore_ extension, two uses jsonb functions and two others iterate through record fields.
5
-
6
- # Usage
7
-
8
- Create database:
9
-
10
- ```sh
11
- make setup
12
- ```
13
-
14
- You can provide database name by `DB` variable (defaults to "logidze_bench").
15
-
16
- Run all benchmarks:
17
-
18
- ```sh
19
- make
20
- ```
21
-
22
- or separate benchmark:
23
-
24
- ```sh
25
- make hstore
26
-
27
- make jsonb
28
-
29
- make jsonb2
30
-
31
- make keys
32
-
33
- make keys2
34
-
35
- # Raw update, no triggers
36
- make plain
37
- ```
38
-
39
- You can specify the number of transactions by `T` variable (defaults to 10000):
40
-
41
- ```sh
42
- make T=1000000
43
- ```
44
-
45
- # Results
46
-
47
- The benchmark shows that hstore variant is the most efficient (running on MacPro 2013, 2.4 GHz Core i5, 4GB, SSD, 1 million transactions per test):
48
-
49
- |Mode | TPS | Statement latency (ms) |
50
- |--------|------|------------------------|
51
- | plain | 3628 | 0.113 |
52
- | hstore | 3015 | 0.168 |
53
- | jsonb | 1647 | 0.363 |
54
- | jsonb2 | 1674 | 0.354 |
55
- | keys | 2355 | 0.219 |
56
- | keys2 | 2542 | 0.210 |
57
-
58
- _Logidze_ uses hstore variant.
@@ -1,6 +0,0 @@
1
- \set naccounts 100000 * :scale
2
- \setrandom aid 1 :naccounts
3
- \setrandom delta -5000 5000
4
- BEGIN;
5
- UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
6
- END;
@@ -1,38 +0,0 @@
1
- CREATE OR REPLACE FUNCTION hstore_logger() RETURNS TRIGGER AS $body$
2
- DECLARE
3
- changes_h jsonb;
4
- size integer;
5
- buffer jsonb;
6
- BEGIN
7
- size := jsonb_array_length(NEW.log);
8
-
9
- changes_h := hstore_to_jsonb_loose(
10
- hstore(NEW.*) - hstore(OLD.*)
11
- );
12
-
13
- NEW.log := jsonb_set(
14
- NEW.log,
15
- ARRAY[size::text],
16
- jsonb_build_object(
17
- 'ts',
18
- extract(epoch from now())::int,
19
- 'i',
20
- (NEW.log#>>ARRAY[(size - 1)::text, 'i'])::int + 1,
21
- 'd',
22
- changes_h
23
- ),
24
- true
25
- );
26
- return NEW;
27
- END;
28
- $body$
29
- LANGUAGE plpgsql;
30
-
31
-
32
- ALTER TABLE pgbench_accounts ADD COLUMN log jsonb DEFAULT '[]' NOT NULL;
33
-
34
- UPDATE pgbench_accounts SET log = to_jsonb(ARRAY[json_build_object('i', 0)])::jsonb;
35
-
36
- CREATE TRIGGER hstore_log_accounts
37
- BEFORE UPDATE ON pgbench_accounts FOR EACH ROW
38
- EXECUTE PROCEDURE hstore_logger();
@@ -1,47 +0,0 @@
1
- CREATE OR REPLACE FUNCTION jsonb_minus(arg1 jsonb, arg2 jsonb) RETURNS jsonb
2
- AS $$
3
-
4
- SELECT
5
- COALESCE(json_object_agg(key, value), '{}')::jsonb
6
- FROM
7
- jsonb_each(arg1)
8
- WHERE NOT jsonb_build_object(key, value) <@ arg2;
9
-
10
- $$ LANGUAGE SQL;
11
-
12
- CREATE OR REPLACE FUNCTION jsonb_minus_2_logger() RETURNS TRIGGER AS $body$
13
- DECLARE
14
- changes_h jsonb;
15
- size integer;
16
- buffer jsonb;
17
- BEGIN
18
- size := jsonb_array_length(NEW.log);
19
-
20
- changes_h := jsonb_minus(row_to_json(OLD)::jsonb, row_to_json(NEW)::jsonb);
21
-
22
- NEW.log := jsonb_set(
23
- NEW.log,
24
- ARRAY[size::text],
25
- jsonb_build_object(
26
- 'ts',
27
- extract(epoch from now())::int,
28
- 'i',
29
- (NEW.log#>>ARRAY[(size - 1)::text, 'i'])::int + 1,
30
- 'd',
31
- changes_h
32
- ),
33
- true
34
- );
35
- return NEW;
36
- END;
37
- $body$
38
- LANGUAGE plpgsql;
39
-
40
-
41
- ALTER TABLE pgbench_accounts ADD COLUMN log jsonb DEFAULT '[]' NOT NULL;
42
-
43
- UPDATE pgbench_accounts SET log = to_jsonb(ARRAY[json_build_object('i', 0)])::jsonb;
44
-
45
- CREATE TRIGGER hstore_log_accounts
46
- BEFORE UPDATE ON pgbench_accounts FOR EACH ROW
47
- EXECUTE PROCEDURE jsonb_minus_2_logger();
@@ -1,49 +0,0 @@
1
- CREATE OR REPLACE FUNCTION jsonb_minus(arg1 jsonb, arg2 jsonb) RETURNS jsonb
2
- AS $$
3
-
4
- SELECT
5
- COALESCE(json_object_agg(key, value), '{}')::jsonb
6
- FROM
7
- jsonb_each(arg1)
8
- WHERE
9
- arg1 -> key <> arg2 -> key
10
- OR arg2 -> key IS NULL;
11
-
12
- $$ LANGUAGE SQL;
13
-
14
- CREATE OR REPLACE FUNCTION jsonb_minus_logger() RETURNS TRIGGER AS $body$
15
- DECLARE
16
- changes_h jsonb;
17
- size integer;
18
- buffer jsonb;
19
- BEGIN
20
- size := jsonb_array_length(NEW.log);
21
-
22
- changes_h := jsonb_minus(row_to_json(OLD)::jsonb, row_to_json(NEW)::jsonb);
23
-
24
- NEW.log := jsonb_set(
25
- NEW.log,
26
- ARRAY[size::text],
27
- jsonb_build_object(
28
- 'ts',
29
- extract(epoch from now())::int,
30
- 'i',
31
- (NEW.log#>>ARRAY[(size - 1)::text, 'i'])::int + 1,
32
- 'd',
33
- changes_h
34
- ),
35
- true
36
- );
37
- return NEW;
38
- END;
39
- $body$
40
- LANGUAGE plpgsql;
41
-
42
-
43
- ALTER TABLE pgbench_accounts ADD COLUMN log jsonb DEFAULT '[]' NOT NULL;
44
-
45
- UPDATE pgbench_accounts SET log = to_jsonb(ARRAY[json_build_object('i', 0)])::jsonb;
46
-
47
- CREATE TRIGGER hstore_log_accounts
48
- BEFORE UPDATE ON pgbench_accounts FOR EACH ROW
49
- EXECUTE PROCEDURE jsonb_minus_logger();
@@ -1,44 +0,0 @@
1
- CREATE OR REPLACE FUNCTION keys_2_logger() RETURNS TRIGGER AS $body$
2
- DECLARE
3
- size integer;
4
- old_j jsonb;
5
- changes_j jsonb;
6
- item record;
7
- BEGIN
8
- size := jsonb_array_length(NEW.log);
9
- old_j := to_jsonb(OLD);
10
- changes_j := to_jsonb(NEW);
11
-
12
- FOR item in SELECT key as k, value as v FROM jsonb_each(old_j)
13
- LOOP
14
- IF changes_j->item.k = item.v THEN
15
- changes_j := changes_j - item.k;
16
- END IF;
17
- END LOOP;
18
-
19
- NEW.log := jsonb_set(
20
- NEW.log,
21
- ARRAY[size::text],
22
- jsonb_build_object(
23
- 'ts',
24
- extract(epoch from now())::int,
25
- 'i',
26
- (NEW.log#>>ARRAY[(size - 1)::text, 'i'])::int + 1,
27
- 'd',
28
- changes_j
29
- ),
30
- true
31
- );
32
- return NEW;
33
- END;
34
- $body$
35
- LANGUAGE plpgsql;
36
-
37
-
38
- ALTER TABLE pgbench_accounts ADD COLUMN log jsonb DEFAULT '[]' NOT NULL;
39
-
40
- UPDATE pgbench_accounts SET log = to_jsonb(ARRAY[json_build_object('i', 0)])::jsonb;
41
-
42
- CREATE TRIGGER keys_log_accounts
43
- BEFORE UPDATE ON pgbench_accounts FOR EACH ROW
44
- EXECUTE PROCEDURE keys_2_logger();
@@ -1,50 +0,0 @@
1
- CREATE OR REPLACE FUNCTION keys_logger() RETURNS TRIGGER AS $body$
2
- DECLARE
3
- changes_h jsonb;
4
- size integer;
5
- old_j jsonb;
6
- new_j jsonb;
7
- item record;
8
- BEGIN
9
- size := jsonb_array_length(NEW.log);
10
- old_j := to_jsonb(OLD);
11
- new_j := to_jsonb(NEW);
12
- changes_h := '{}'::jsonb;
13
-
14
- FOR item in SELECT key as k, value as v FROM jsonb_each(new_j)
15
- LOOP
16
- IF item.v <> jsonb_extract_path(old_j, item.k) THEN
17
- changes_h := jsonb_set(
18
- changes_h,
19
- ARRAY[item.k],
20
- item.v
21
- );
22
- END IF;
23
- END LOOP;
24
-
25
- NEW.log := jsonb_set(
26
- NEW.log,
27
- ARRAY[size::text],
28
- jsonb_build_object(
29
- 'ts',
30
- extract(epoch from now())::int,
31
- 'i',
32
- (NEW.log#>>ARRAY[(size - 1)::text, 'i'])::int + 1,
33
- 'd',
34
- changes_h
35
- ),
36
- true
37
- );
38
- return NEW;
39
- END;
40
- $body$
41
- LANGUAGE plpgsql;
42
-
43
-
44
- ALTER TABLE pgbench_accounts ADD COLUMN log jsonb DEFAULT '[]' NOT NULL;
45
-
46
- UPDATE pgbench_accounts SET log = to_jsonb(ARRAY[json_build_object('i', 0)])::jsonb;
47
-
48
- CREATE TRIGGER keys_log_accounts
49
- BEFORE UPDATE ON pgbench_accounts FOR EACH ROW
50
- EXECUTE PROCEDURE keys_logger();
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "rails"
5
- require "logidze"
6
-
7
- require "pry"
8
- Pry.start
data/bin/setup DELETED
@@ -1,9 +0,0 @@
1
- #!/bin/sh
2
-
3
- set -e
4
-
5
- gem install bundler --conservative
6
- bundle check || bundle install
7
-
8
- RAILS_ENV=test bundle exec rake dummy:db:create
9
- RAILS_ENV=test bundle exec rake dummy:db:migrate
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rails', '~> 4.2'
4
- gem 'pg', '~> 0.18'
5
-
6
- gemspec path: '..'
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rails', '~> 5.1.0'
4
- gem 'rspec-rails', '~> 3.5'
5
-
6
- gemspec path: '..'
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rails', '~> 5.2.1'
4
- gem 'rspec-rails', '~> 3.5'
5
-
6
- gemspec path: '..'
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rails', '~> 6.0'
4
- gem 'rspec-rails', '>= 3.5'
5
-
6
- gemspec path: '..'