logidze 0.12.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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: '..'