Skip to content
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3ca7944
feat: `logidze_data` table generator
Lokideos Feb 16, 2025
3c9d45d
feat: read methods for detached behavior
Lokideos Feb 17, 2025
6e8094e
feat: detached trigger; reset logs; snapshots; detached model generation
Lokideos Feb 18, 2025
29ffad4
feat: benchmarks
Lokideos Feb 18, 2025
b889aec
feat: detached after-trigger implementation
Lokideos Feb 18, 2025
bf32ae7
docs: update changelog and readme
Lokideos Feb 18, 2025
2549c87
fix: fix data generation for benchmarks
Lokideos Feb 19, 2025
564c944
fix: fix issue with long index name
Lokideos Feb 19, 2025
5d6a3db
fix: fix spec for prefixed tables
Lokideos Feb 19, 2025
fb2e55f
docs: add notice about performance drop to readme
Lokideos Feb 19, 2025
3506c8f
docs: fix styling for memory profiling results
Lokideos Feb 19, 2025
fccea0b
docs: add --detached option link to table of contents
Lokideos Feb 19, 2025
7ca570b
fix: detachable refactoring
Lokideos Feb 19, 2025
1ff4ae9
feat: .reset_log_data and #reset_log_data scope fix and refactoring
Lokideos Feb 20, 2025
f75d8cc
refactor: make #build_dup flexible
Lokideos Feb 21, 2025
96dd316
refactor: include detached SQL function in `logidze_logger()` function
Lokideos Feb 21, 2025
0445454
refactor: fallback to Rails::Generators::NamedBase for `class_name`
Lokideos Feb 21, 2025
05f3407
refactor: avoid loading LogidzeData on gem initialization
Lokideos Feb 21, 2025
cc2789c
refactor: reload `log_data` using AssociationProxy API
Lokideos Feb 21, 2025
1be3797
refactor: remove `#switch_to!` reimplementation
Lokideos Feb 21, 2025
c77e774
fix: preload `logidze_data` for Class methods
Lokideos Feb 22, 2025
916259d
fix: update benchmarks
Lokideos Feb 22, 2025
e24c90c
refactor: move includes scope to private method
Lokideos Feb 23, 2025
4d8dd88
refactor: add integration tests for --detached
Lokideos Feb 24, 2025
7c1c14e
refactor: merge detachable specs into model test suite
Lokideos Feb 24, 2025
78c3769
fix: adjust --detached functionality for prefixed tables
Lokideos Feb 24, 2025
07a8246
refactor: rollback logidze_logger name change
Lokideos Feb 25, 2025
2e41573
refactor: pass vars to EXECUTE via USING
Lokideos Feb 25, 2025
53fad60
refactor: update benchmark
Lokideos Feb 25, 2025
8cc81c3
fix: re-use specs and text fixtures for detached mode
palkan Mar 18, 2025
943810a
fix: Take into account new migration in specs
Lokideos Mar 19, 2025
b31ee59
fix: Add missing detachable route in spec
Lokideos Mar 19, 2025
f43b8bf
fix: Do not add logidze macros if it exists
Lokideos Mar 19, 2025
108a862
fix: Remove spec call to non-existing model
Lokideos Mar 21, 2025
eb05305
fix: Correctly resolve path to versioned model
Lokideos Mar 21, 2025
4516e69
fix: Reset column cache before test suite setup
Lokideos Mar 30, 2025
531d764
refactor: Upsert on snapshots creation
Lokideos Apr 1, 2025
227c1e0
refactor: DRY snapshot creation
Lokideos Apr 1, 2025
6dbce7e
refactor: Detach snapshot args generation
Lokideos Apr 1, 2025
0dc3ae3
docs: Correct wording for detached mode readme
Lokideos Apr 1, 2025
b372e90
refactor: Simplify env-based specs setup
Lokideos Apr 7, 2025
0bb4c06
refactor: Improve Env-based specs setup
Lokideos Apr 9, 2025
f1600ad
refactor: Upsert logidze_data records in backfill migrations
Lokideos Apr 9, 2025
806268f
fix: migration style
palkan Apr 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/rspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ jobs:
gemfile: rails8.gemfile
fx: "false"
after_trigger: "false"
- ruby: "3.4"
postgres: "16"
gemfile: rails8.gemfile
fx: "true"
after_trigger: "false"
detached: "true"
- ruby: "3.3"
postgres: "16"
gemfile: rails8.gemfile
Expand Down Expand Up @@ -109,6 +115,7 @@ jobs:
USE_FX: ${{ matrix.fx }}
TABLE_NAME_PREFIX: ${{ matrix.table_name_prefix }}
TABLE_NAME_SUFFIX: ${{ matrix.table_name_suffix }}
LOGIDZE_DETACHED: ${{ matrix.detached }}
run: |
bundle exec rspec --exclude-pattern=spec/acceptance/**/* -f d --force-color
- name: Run RSpec (acceptance)
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ spec/dummy/db/functions/
spec/dummy/db/triggers/
spec/dummy/db/migrate/*_enable_hstore.rb
spec/dummy/db/migrate/*_logidze_install.rb
spec/dummy/db/migrate/*_logidze_data.rb

Gemfile.lock
Gemfile.local
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## master (unreleased)

- Support Rails 7.2 ([@atomaka][])
- Add `--detached` option to store `log_data` in a separate `logidze_data` table to avoid table bloat.

## 1.3.1 (2024-10-23)

Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Other requirements:
- [Logs timestamps](#logs-timestamps)
- [Undoing a Generated Invocation](#undoing-a-generated-invocation)
- [Using with partitioned tables](#using-with-partitioned-tables)
- [Storing history data in a separate table](#storing-history-data-in-a-separate-table)
- [Usage](#usage)
- [Basic API](#basic-api)
- [Track meta information](#track-meta-information)
Expand Down Expand Up @@ -203,6 +204,17 @@ bundle exec rails generate logidze:model Post --after-trigger

**IMPORTANT:** Using Logidze for partitioned tables in PostgreSQL 10 is not supported.

### Storing history data in a separate table

By default, Logidze stores history data in the `log_data` column in the origin record table, which might lead to table bloat.
If it concerns you, you may configure Logidze to store history data in a separate table by providing `--detached` option to the migration:

```sh
bundle exec rails logidze:model Post --detached
```

**IMPORTANT:** Using `--detached` mode for storing historic data slightly decreases performance. Check [bench results] for the details.

## Usage

### Basic API
Expand Down Expand Up @@ -645,3 +657,4 @@ Bug reports and pull requests are welcome on GitHub at [https://github.com/palka
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).

[fx]: https://github.com/teoljungberg/fx
[bench results]: https://github.com/palkan/logidze/blob/feat-log-data-separate-storage/bench/performance/README.md
9 changes: 9 additions & 0 deletions app/models/logidze/logidze_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module Logidze
class LogidzeData < ::ApplicationRecord
attribute :log_data, Logidze::History::Type.new

belongs_to :loggable, polymorphic: true
end
end
4 changes: 2 additions & 2 deletions bench/performance/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

source "https://rubygems.org"

gem "rails", "~> 6.0"
gem "rails", "~> 7.0"
gem "pg", "~> 1.0"

gem "paper_trail", "~> 10.0"
gem "paper_trail", "~> 15.0"
gem "logidze", path: "../../.."
gem "fx"

Expand Down
102 changes: 61 additions & 41 deletions bench/performance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ bundle exec ruby benchmarks/insert_bench.rb

```sh
Comparison:
Plain INSERT: 535.5 i/s
Logidze INSERT: 498.2 i/s - same-ish: difference falls within error
PaperTrail INSERT: 276.5 i/s - 1.94x (± 0.00) slower
Plain INSERT: 450.9 i/s
Logidze INSERT: 408.2 i/s - same-ish: difference falls within error
LogidzeDetached INSERT: 359.8 i/s - same-ish: difference falls within error
PaperTrail INSERT: 183.9 i/s - same-ish: difference falls within error
```

## Update ([source](benchmarks/update_bench.rb))
Expand All @@ -30,18 +31,20 @@ When changeset has 2 fields:

```sh
Comparison:
Plain UPDATE #1: 775.2 i/s
Logidze UPDATE #1: 518.6 i/s - 1.49x (± 0.00) slower
PT UPDATE #1: 471.4 i/s - 1.64x (± 0.00) slower
Plain UPDATE #1: 204.8 i/s
LogidzeDetached UPDATE #1: 188.4 i/s - same-ish: difference falls within error
Logidze UPDATE #1: 175.7 i/s - same-ish: difference falls within error
PT UPDATE #1: 114.2 i/s - same-ish: difference falls within error
```

When changeset has 5 fields:

```sh
Comparison:
Plain UPDATE #2: 726.8 i/s
Logidze UPDATE #2: 468.0 i/s - 1.55x (± 0.00) slower
PT UPDATE #2: 431.2 i/s - 1.69x (± 0.00) slower
Plain UPDATE #2: 117.8 i/s
Logidze Detached UPDATE #2: 116.1 i/s - same-ish: difference falls within error
Logidze UPDATE #2: 115.4 i/s - same-ish: difference falls within error
PT UPDATE #2: 57.6 i/s - 2.04x slower
```

## Getting diff ([source](benchmarks/diff_bench.rb))
Expand All @@ -53,18 +56,21 @@ When each record has 10 versions:

```sh
Comparison:
Logidze DIFF: 129.2 i/s
PT (join) DIFF: 4.5 i/s - 28.57x (± 0.00) slower
PT DIFF: 3.9 i/s - 32.83x (± 0.00) slower
Logidze DIFF: 189.2 i/s
LogidzeDetached DIFF: 124.0 i/s - 1.52x slower
PT (join) DIFF: 4.4 i/s - 42.82x slower
PT DIFF: 3.1 i/s - 60.69x slower
```

When each record has 100 versions:

```sh

Comparison:
Logidze DIFF: 32.8 i/s
PT (join) DIFF: 0.5 i/s - 69.48x (± 0.00) slower
PT DIFF: 0.4 i/s - 88.81x (± 0.00) slower
Logidze DIFF: 78.5 i/s
LogidzeDetached DIFF: 69.8 i/s - 1.13x slower
PT DIFF: 0.4 i/s - 200.20x slower
PT (join) DIFF: 0.3 i/s - 227.26x slower
```

## Getting version at the specified time ([source](benchmarks/version_at_bench.rb))
Expand All @@ -75,24 +81,28 @@ When each record has 10 versions:

```sh
Comparison:
Logidze AT single: 882.1 i/s
PT AT single: 336.7 i/s - 2.62x (± 0.00) slower
Logidze AT single: 468.3 i/s
LogidzeDetached AT single: 262.3 i/s - same-ish: difference falls within error
PT AT single: 169.6 i/s - 2.76x slower

Comparison:
Logidze AT many: 265.0 i/s
PT AT many: 43.9 i/s - 6.04x (± 0.00) slower
Logidze AT many: 283.7 i/s
LogidzeDetached AT many: 199.3 i/s - 1.42x slower
PT AT many: 27.0 i/s - 10.52x slower
```

When each record has 100 versions:

```sh
Comparison:
Logidze AT single: 543.0 i/s
PT AT single: 337.8 i/s - 1.61x (± 0.00) slower
Logidze AT single: 339.2 i/s
LogidzeDetached AT single: 219.6 i/s - same-ish: difference falls within error
PT AT single: 150.3 i/s - 2.26x slower

Comparison:
Logidze AT many: 92.0 i/s
PT AT many: 45.3 i/s - 2.03x (± 0.00) slower
Logidze AT many: 167.9 i/s
LogidzeDetached AT many: 130.2 i/s - 1.29x slower
PT AT many: 24.2 i/s - 6.94x slower
```

**NOTE:** PaperTrail has N+1 problem when loading multiple records at the specified time (due to the usage of the `versions.subsequent` method).
Expand All @@ -105,36 +115,46 @@ When each record has 10 versions:

```sh
Plain records
Total Allocated: 15.24 KB
Total Retained: 9.68 KB
Retained_memsize memory (per record): 1.12 KB
Total Allocated: 44.38 KB
Total Retained: 22.52 KB
Retained_memsize memory (per record): 2.35 KB

PT with versions
Total Allocated: 124.38 KB
Total Retained: 95.52 KB
Retained_memsize memory (per record): 81.82 KB
Total Allocated: 387.58 KB
Total Retained: 223.77 KB
Retained_memsize memory (per record): 203.13 KB

Logidze records
Total Allocated: 38.68 KB
Total Retained: 32.12 KB
Retained_memsize memory (per record): 3.54 KB
Total Allocated: 76.37 KB
Total Retained: 38.46 KB
Retained_memsize memory (per record): 3.72 KB

LogidzeDetached records
Total Allocated: 53.84 KB
Total Retained: 24.1 KB
Retained_memsize memory (per record): -1768 B
```

When each record has 100 versions:

```sh
Plain records
Total Allocated: 15.22 KB
Total Retained: 9.66 KB
Retained_memsize memory (per record): 1.11 KB
Total Allocated: 44.3 KB
Total Retained: 22.48 KB
Retained_memsize memory (per record): 2.23 KB

PT with versions
Total Allocated: 998.71 KB
Total Retained: 864.26 KB
Retained_memsize memory (per record): 850.6 KB
Total Allocated: 3.32 MB
Total Retained: 1.99 MB
Retained_memsize memory (per record): 1.97 MB

Logidze records
Total Allocated: 140.16 KB
Total Retained: 133.6 KB
Retained_memsize memory (per record): 13.91 KB
Total Allocated: 281.22 KB
Total Retained: 140.89 KB
Retained_memsize memory (per record): 14.16 KB

LogidzeDetached records
Total Allocated: 53.29 KB
Total Retained: 23.83 KB
Retained_memsize memory (per record): -1608 B
```
6 changes: 6 additions & 0 deletions bench/performance/app/lib/benchmarker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def populate(n = 1_000, skip_user: false)
User.create!(params) unless skip_user
PaperTrailUser.create!(params)
LogidzeUser.create!(params)
LogidzeDetachedUser.create!(params)
end

$stdout.puts "Done in #{Time.current - ts}s"
Expand All @@ -23,6 +24,7 @@ def cleanup
PaperTrailUser.delete_all
User.delete_all
PaperTrail::Version.delete_all
LogidzeDetachedUser.delete_all
end

def generate_versions(num = 1)
Expand All @@ -39,6 +41,10 @@ def generate_versions(num = 1)
u.update!(fake_params(sample: true))
end

LogidzeDetachedUser.find_each do |u|
u.update!(fake_params(sample: true))
end

# make at least 1 second between versions
sleep 1
end
Expand Down
5 changes: 5 additions & 0 deletions bench/performance/app/models/logidze_detached_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class LogidzeDetachedUser < ApplicationRecord
has_logidze detached: true
end
4 changes: 4 additions & 0 deletions bench/performance/benchmarks/diff_bench.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@
LogidzeUser.random(N / 2).diff_from(time: ts1)
end

x.report("LogidzeDetached DIFF") do
LogidzeDetachedUser.random(N / 2).diff_from(time: ts1)
end

x.compare!
end
4 changes: 4 additions & 0 deletions bench/performance/benchmarks/insert_bench.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@
LogidzeUser.create!(params)
end

x.report("LogidzeDetached INSERT") do
LogidzeDetachedUser.create!(params)
end

x.compare!
end
5 changes: 4 additions & 1 deletion bench/performance/benchmarks/memory_profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ module MemoryReport

module_function

def call(msg, relation)
def call(msg, relation, gc_disable: true)
GC.disable if gc_disable

buffer = nil
delta = N / 10
r0 = MemoryProfiler.report do
Expand Down Expand Up @@ -54,3 +56,4 @@ def to_human_size(size)
MemoryReport.call("Plain records", User.all)
MemoryReport.call("PT with versions", PaperTrailUser.joins(:versions).all)
MemoryReport.call("Logidze records", LogidzeUser.all)
MemoryReport.call("LogidzeDetached records", LogidzeDetachedUser.joins(:logidze_data).all)
10 changes: 10 additions & 0 deletions bench/performance/benchmarks/update_bench.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class LogidzeUser
LogidzeUser.random.update!(params)
end

x.report("LogidzeDetached UPDATE #1") do
LogidzeDetachedUser.random.update!(params)
end

x.compare!
end

Expand All @@ -60,5 +64,11 @@ class LogidzeUser
user.update!(params2.slice(*JSON_COLUMNS))
end

x.report("Logidze Detached UPDATE #2") do
user = LogidzeDetachedUser.random
user.update!(params2.except(*JSON_COLUMNS))
user.update!(params2.slice(*JSON_COLUMNS))
end

x.compare!
end
8 changes: 8 additions & 0 deletions bench/performance/benchmarks/version_at_bench.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
LogidzeUser.random.at(time: ts1)
end

x.report("LogidzeDetached AT single") do
LogidzeDetachedUser.random.at(time: ts1)
end

x.compare!
end

Expand All @@ -48,5 +52,9 @@
LogidzeUser.random(M).at(time: ts1)
end

x.report("LogidzeDetached AT many") do
LogidzeDetachedUser.random(M).at(time: ts1)
end

x.compare!
end
5 changes: 5 additions & 0 deletions bench/performance/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@ class Application < Rails::Application

config.logger = ENV["LOG"] ? Logger.new($stdout) : Logger.new(IO::NULL)
config.active_record.dump_schema_after_migration = false
config.active_record.yaml_column_permitted_classes = [
ActiveSupport::TimeWithZone,
ActiveSupport::TimeZone,
Time
]
end
end
Loading
Loading