diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2015-10-15 13:33:15 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2015-10-15 13:33:42 -0700 |
commit | 3253185b363da4e98a63f3f82b94e8e5e33154c9 (patch) | |
tree | 23a036b3f357dcd0273804baa57d0bd6c67dcecc /actionmailer/test | |
parent | 3acc590d5080279fe726ac978b713304e11f35da (diff) | |
download | rails-3253185b363da4e98a63f3f82b94e8e5e33154c9.tar.gz rails-3253185b363da4e98a63f3f82b94e8e5e33154c9.tar.bz2 rails-3253185b363da4e98a63f3f82b94e8e5e33154c9.zip |
make string allocation constant regardless of column count
deep_dup'ing a hash will dup the keys as well as the values. Since
string keys from the source hash will be frozen, and the dup'd objects
are immediately dup'd and frozen on insert in to the hash, the end user
will only ever see two frozen strings. Since the strings are immutable,
this commit just cheats a little and reuses the immutable strings.
Just to reiterate, before this commit, deep duping a hash that looks
like this: `{ "foo" => "bar" }` will generate two new instances of
"foo". One is created when `deep_dup` is called on "foo", and the other
is created when the newly allocated "foo" string is inserted in to the
hash. The user never sees the intermediate "foo", and both copies of
"foo" that the user *can* access will be frozen, so in this case we just
reuse the existing frozen key.
The upshot is that after this change, string allocations on AR
allocations become constant regardless of the number of columns the
model has.
```ruby
require 'active_record'
class Topic < ActiveRecord::Base
end
20.times do |i|
Process.waitpid fork {
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
ActiveRecord::Base.connection.instance_eval do
create_table(:topics) do |t|
t.string :title, limit: 250
t.string :author_name
t.string :author_email_address
t.string :parent_title
t.string :type
t.string :group
i.times do |j|
t.integer :"aaa#{j}"
end
t.timestamps null: true
end
end
ObjectSpace::AllocationTracer.setup(%i{type})
Topic.create title: "aaron" # heat cache
result = ObjectSpace::AllocationTracer.trace do
10.times do |i|
Topic.create title: "aaron #{i}"
end
end
puts "#{Topic.columns.length},#{(result.find { |k,v| k.first == :T_STRING }.last.first / 10)}"
}
end
```
If you run the above script before this commit, the output looks like
this:
```
[aaron@TC rails (master)]$ be ruby -rallocation_tracer test.rb
9,105
10,107
11,109
12,111
13,113
14,115
15,117
16,119
17,121
18,123
19,125
20,127
21,129
22,131
23,133
24,135
25,137
26,139
27,141
28,143
```
The left column is the number of methods, the right column is the number
of string allocations.
Running against this commit, the output is:
```
[aaron@TC rails (master)]$ be ruby -rallocation_tracer test.rb
9,87
10,87
11,87
12,87
13,87
14,87
15,87
16,87
17,87
18,87
19,87
20,87
21,87
22,87
23,87
24,87
25,87
26,87
27,87
28,87
```
As you can see, there is now only a constant number of strings
allocated, regardless of the number of columns the model has.
Diffstat (limited to 'actionmailer/test')
0 files changed, 0 insertions, 0 deletions