| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
| |
When an `updated_at` column exists on the model, but is not available on the instance (likely due to a select), we should raise an error rather than silently not generating a cache_version. Without this behavior it's likely that cache entries will not be able to be invalidated and this will happen without notice.
This behavior was reported and described by @lsylvester in https://github.com/rails/rails/pull/34197#issuecomment-429668759.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Currently, the `updated_at` field is used to generate a `cache_version`. Some database adapters return this timestamp value as a string that must then be converted to a Time value. This process requires a lot of memory and even more CPU time. In the case where this value is only being used for a cache version, we can skip the Time conversion by using the string value directly.
- This PR preserves existing cache format by converting a UTC string from the database to `:usec` format.
- Some databases return an already converted Time object, in those instances, we can directly use `created_at`.
- The `updated_at_before_type_cast` can be a value that comes from either the database or the user. We only want to optimize the case where it is from the database.
- If the format of the cache version has been changed, we cannot apply this optimization, and it is skipped.
- If the format of the time in the database is not UTC, then we cannot use this optimization, and it is skipped.
Some databases (notably PostgreSQL) returns a variable length nanosecond value in the time string. If the value ends in a zero, then it is truncated For instance instead of `2018-10-12 05:00:00.000000` the value `2018-10-12 05:00:00` is returned. We detect this case and pad the remaining zeros to ensure consistent cache version generation.
Before: Total allocated: 743842 bytes (6626 objects)
After: Total allocated: 702955 bytes (6063 objects)
(743842 - 702955) / 743842.0 # => 5.4% ⚡️⚡️⚡️⚡️⚡️
Using the CodeTriage application and derailed benchmarks this PR shows between 9-11% (statistically significant) performance improvement versus the commit before it.
Special thanks to @lsylvester for helping to figure out a way to preserve the usec format and for helping with many implementation details.
|
|\
| |
| | |
ActiveRecord#respond_to? No longer allocates strings
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This is an alternative to https://github.com/rails/rails/pull/34195
The active record `respond_to?` method needs to do two things if `super` does not say that the method exists. It has to see if the "name" being passed in represents a column in the table. If it does then it needs to pass it to `has_attribute?` to see if the key exists in the current object. The reason why this is slow is that `has_attribute?` needs a string and most (almost all) objects passed in are symbols.
The only time we need to allocate a string in this method is if the column does exist in the database, and since these are a limited number of strings (since column names are a finite set) then we can pre-generate all of them and use the same string.
We generate a list hash of column names and convert them to symbols, and store the value as the string name. This allows us to both check if the "name" exists as a column, but also provides us with a string object we can use for the `has_attribute?` call.
I then ran the test suite and found there was only one case where we're intentionally passing in a string and changed it to a symbol. (However there are tests where we are using a string key, but they don't ship with rails).
As re-written this method should never allocate unless the user passes in a string key, which is fairly uncommon with `respond_to?`.
This also eliminates the need to special case every common item that might come through the method via the `case` that was originally added in https://github.com/rails/rails/commit/f80aa5994603e684e3fecd3f53bfbf242c73a107 (by me) and then with an attempt to extend in https://github.com/rails/rails/pull/34195.
As a bonus this reduces 6,300 comparisons (in the CodeTriage app homepage) to 450 as we also no longer need to loop through the column array to check for an `include?`.
|
| |
| |
| |
| | |
Follow up #32146.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`init_with` and `init_from_db` are almost the same code except decode
`coder`.
And also, named `init_from_db` is a little misreading, a raw values hash
from the database is already converted to an attributes object by
`attributes_builder.build_from_database`, so passed `attributes` in that
method is just an attributes object.
I renamed that method to `init_with_attributes` since the method is
shared with `init_with` to initialize an empty model object.
|
| |
| |
| |
| |
| |
| |
| | |
I don't prefer to extract it for one adapter even though all adapters
also does.
Related to #34227.
|
|\ \
| | |
| | | |
Refactored abstract MySQL adapter to support lazy version check.
|
| |/
| |
| |
| |
| |
| |
| |
| |
| | |
Will allow sub classes to override the protected
`#check_version` method hook if desired.
For example, this will be most helpful in sub classes that wish
to support lazy initialization because the version check can
be postponed until the connection is ready to be initialized.
|
|/
|
|
| |
Change query to use alias name for timestamp_column to avoid ambiguity problems when using timestamp from subquery.
|
|
|
|
|
|
|
|
| |
Ruby uses the original method name, so will show the __temp__ method
name in the backtrace. However, in the common case the method name
is compatible with the `def` keyword, so we can avoid the __temp__
method name in that case to improve the name shown in backtraces
or TracePoint#method_id.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This PR adds the ability to 1) connect to multiple databases in a model,
and 2) switch between those connections using a block.
To connect a model to a set of databases for writing and reading use
the following API. This API supercedes `establish_connection`. The
`writing` and `reading` keys represent handler / role names and
`animals` and `animals_replica` represents the database key to look up
the configuration hash from.
```
class AnimalsBase < ApplicationRecord
connects_to database: { writing: :animals, reading: :animals_replica }
end
```
Inside the application - outside the model declaration - we can switch
connections with a block call to `connected_to`.
If we want to connect to a db that isn't default (ie readonly_slow) we
can connect like this:
Outside the model we may want to connect to a new database (one that is
not in the default writing/reading set) - for example a slow replica for
making slow queries. To do this we have the `connected_to` method that
takes a `database` hash that matches the signature of `connects_to`. The
`connected_to` method also takes a block.
```
AcitveRecord::Base.connected_to(database: { slow_readonly: :primary_replica_slow }) do
ModelInPrimary.do_something_thats_slow
end
```
For models that are already loaded and connections that are already
connected, `connected_to` doesn't need to pass in a `database` because
you may want to run queries against multiple databases using a specific
role/handler.
In this case `connected_to` can take a `role` and use that to swap on
the connection passed. This simplies queries - and matches how we do it
in GitHub. Once you're connected to the database you don't need to
re-connect, we assume the connection is in the pool and simply pass the
handler we'd like to swap on.
```
ActiveRecord::Base.connected_to(role: :reading) do
Dog.read_something_from_dog
ModelInPrimary.do_something_from_model_in_primary
end
```
|
|\
| |
| |
| |
| | |
albertoalmagro/enum-raises-on-invalid-definition-values
Enum raises on invalid definition values
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When defining a Hash enum it can be easy to use [] instead of {}. This
commit checks that only valid definition values are provided, those can
be a Hash, an array of Symbols or an array of Strings. Otherwise it
raises an ArgumentError.
Fixes #33961
|
|\ \
| |/
|/| |
Add multi-db support to rails db:migrate:status
|
| | |
|
|\ \
| | |
| | | |
Generate delegation methods to named scope in the definition time
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
The delegation methods to named scope are defined when `method_missing`
is invoked on the relation.
Since #29301, the receiver in the named scope is changed to the relation
like others (e.g. `default_scope`, etc) for consistency.
Most named scopes would be delegated from relation by `method_missing`,
since we don't allow scopes to be defined which conflict with instance
methods on `Relation` (#31179). But if a named scope is defined with the
same name as any method on the `superclass` (e.g. `Kernel.open`), the
`method_missing` on the relation is not invoked.
To address the issue, make the delegation methods to named scope is
generated in the definition time.
Fixes #34098.
|
|\ \ \
| | | |
| | | |
| | | |
| | | | |
christophemaximin/fix-activerecord-clearing-of-query-cache
Fix inconsistent behavior by clearing QueryCache when reloading associations
|
| | | | |
|
| | | | |
|
| |_|/
|/| | |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Before:
```
Pet Destroy (0.8ms) DELETE FROM `pets` WHERE `pets`.`pet_id` IN (SELECT `pet_id` FROM (SELECT DISTINCT `pets`.`pet_id` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ?) AS __active_record_temp) [["name", "Bone"]]
```
After:
```
Pet Destroy (1.0ms) DELETE `pets` FROM `pets` LEFT OUTER JOIN `toys` ON `toys`.`pet_id` = `pets`.`pet_id` WHERE `toys`.`name` = ? [["name", "Bone"]]
```
|
|\ \ \
| | | |
| | | | |
Move db:migrate:status to DatabaseTasks method
|
| | |/
| |/| |
|
|\ \ \
| |/ /
|/| |
| | |
| | |
| | |
| | | |
aergonaut/docs/ActiveRecord--Persistence-belongs_to_touch_method
Add docs to ActiveRecord::Persistence#belongs_to_touch_method
[ci skip]
|
| | |
| | |
| | |
| | | |
[ci skip]
|
| | | |
|
| | | |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Since #31575, `set_inverse_instance` replaces the foreign key by the
current owner immediately to make it happen when a record is added to
collection association.
But `set_inverse_instance` is not only called when a record is added,
but also when a record is loaded from queries. And also, that loaded
records are not always associated records for some reason (using `or`,
`unscope`, `rewhere`, etc).
It is hard to distinguish whether or not we should invoke
`set_inverse_instance`, but at least we should avoid the undesired
side-effect which was brought from #31575.
Fixes #34108.
|
| | |
| | |
| | |
| | | |
FixtureSet::TableRows
|
| | | |
|
| | | |
|
| | | |
|
| | |
| | |
| | |
| | | |
methods
|
| |/
|/| |
|
| | |
|
| |
| |
| |
| | |
Since the above comment is for the `preloaders_for_one`.
|
|\ \
| | |
| | | |
ActiveRecord::Associations::Preloader should not fail to preload through missing records
|
| | |
| | |
| | |
| | | |
missing records
|
| | |
| | |
| | |
| | |
| | | |
`establish_connection` will never raise `ActiveRecord::NoDatabaseError`,
because it doesn't connect to a database; it sets up a connection pool.
|
| | | |
|
| | | |
|
|/ / |
|
| | |
|
|\ \
| | |
| | |
| | | |
index option added for change_table migrations
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
In case if we want to add a column into the existing table
with index on it, we have to add column and index in two
seperate lines.
With this feature we don't need to write an extra line to
add index for column. We can just use `index` option.
Old behaviour in action:
```
change_table(:languages) do |t|
t.string :country_code
t.index: :country_code
end
```
New behaviour in action:
```
change_table(:languages) do |t|
t.string :country_code, index: true
end
```
Exactly same behaviour is already exist for `create_table` migrations.
|
|\ \ \
| | | |
| | | | |
Add `Style/RedundantFreeze` to remove redudant `.freeze`
|