Commit Graph

9599 Commits

Author SHA1 Message Date
Jonathan Hefner
ea46a00a9f
Merge pull request #50192 from sbfaulkner/memory-store-unless-exist
Fix MemoryStore#write with unless_exist and namespace
2023-11-28 12:25:29 -06:00
S. Brent Faulkner
701377c6af
Fix MemoryStore#write with unless_exist and namespace
Updates `MemoryStore#write_entry` to pass a `nil` `namespace` to
`exist?`, which expects a _name_ rather than a an already "normalized"
_key_. This fixes a bug where `unless_exist` would overwrite any
existing entry if a `namespace` was used.
2023-11-28 13:08:55 -05:00
Kevin McPhillips
9b03df5626 Add some behaviour to ActiveSupport::InheritableOptions to make it quack more like a hash 2023-11-28 12:01:10 -05:00
Jean Boussier
b07362cffa ActiveSupport::Testing::Isolation: gracefully handle the subprocess dying
Right now if the subprocess exit uncleanly, it straight out bring the
parent down with it because it will fail to parse the (likely empty)
Marshal payload:

```
<internal:marshal>:34:in `load': marshal data too short (ArgumentError)
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:23:in `run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:1094:in `run_one_method'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:179:in `block in run'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:168:in `with_timestamps'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:178:in `run'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:229:in `block in run_from_queue'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/ci/queue/redis/worker.rb:55:in `poll'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:228:in `run_from_queue'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:213:in `__run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:162:in `run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:86:in `block in autorun'
 - XXXX::XXXXTest#test_xxxxx - /tmp/bundle/ruby/3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:52:in `write': closed stream (IOError)
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:52:in `puts'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:52:in `block (2 levels) in run_in_isolation'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:32:in `fork'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:32:in `block in run_in_isolation'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:28:in `pipe'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:28:in `run_in_isolation'
	from 3.3.0+0/bundler/gems/rails-488a7ce18880/activesupport/lib/active_support/testing/isolation.rb:19:in `run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:1094:in `run_one_method'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:179:in `block in run'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:168:in `with_timestamps'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:178:in `run'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:229:in `block in run_from_queue'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/ci/queue/redis/worker.rb:55:in `poll'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:228:in `run_from_queue'
	from 3.3.0+0/gems/ci-queue-0.38.0/lib/minitest/queue.rb:213:in `__run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:162:in `run'
	from 3.3.0+0/gems/minitest-5.20.0/lib/minitest.rb:86:in `block in autorun'
```

This breaks the Minitest contract that `run_one_method` shouldn't raise
ever, and return a `Minitest::Result`.

By properly checking the sub process status, we can turn this crash into
a test failure, allowing the original test process to go on.
2023-11-28 14:03:59 +01:00
Jonathan Hefner
04f29cb134 Format inline code [ci-skip] 2023-11-23 11:56:56 -06:00
Jean Boussier
2f19782dce ErrorReporter#unexpected to report in production but raise in development
It's a common useful pattern for situation where something isn't
supposed to happen, but if it does we can recover from it.

So in such situation you don't want such issue to be hidden
in development or test, as it's likely a bug, but do not want to
fail a request if it happens in production.

In other words, it behaves like `#record` in development and test
environments, and like `raise` in production.

Fix: https://github.com/rails/rails/pull/49638
Fix: https://github.com/rails/rails/pull/49339

Co-Authored-By: Andrew Novoselac <andrew.novoselac@shopify.com>
Co-Authored-By: Dustin Brown <dbrown9@gmail.com>
2023-11-20 09:42:56 +01:00
Adam Renberg Tamm
2251a4ba07 Adjust instr. for Cache::Store#fetch_multi so writes are after reads 2023-11-17 11:33:07 +01:00
Sander Verdonschot
4cfdcfef8e
Make return values of Cache::Store#write consistent
The return value was not specified before. Now it returns `true` on a
successful write, `nil` if there was an error talking to the cache
backend, and `false` if the write failed for another reason (e.g. the
key already exists and `unless_exist: true` was passed).
2023-11-16 08:54:23 -05:00
Jean Boussier
514a903431 Fix next Rails version in a deprecation message 2023-11-14 13:12:34 +01:00
Jean Boussier
37b0c603d5 Formally deprecate passing caller to Deprecation#warn
This emitted a warning since 2015, but it's likely most
offenders never saw it.

Ref: 211f55d4fd
2023-11-14 10:33:15 +01:00
Jean Boussier
c2be3ea65c ActiveSupport::Deprecation handle blaming generated code
Fix: #50047

`Backtrace::Location` instance for code generated with eval always
have their `absolute_path` set to `nil`. So if absolute path is nil
we should fallback to checking `#path`.

Co-Authored-By: fatkodima <fatkodima123@gmail.com>
2023-11-14 09:51:41 +01:00
Hartley McGuire
9af99bfffc Fix logged cache key normalization
Previously, the `Cache::Store` instrumentation would call
`normalize_key` when adding a key to the log. However, this resulted in
the logged key not always matching the actual key written/read from the
cache:

```irb
irb(main):004> cache.write("foo", "bar", namespace: "baz")
D, [2023-11-10T12:44:59.286362 #169586] DEBUG -- : Cache write: baz:foo ({:compress=>false, :compress_threshold=>1024, :namespace=>"baz"})
=> true
irb(main):005> cache.delete("foo", namespace: "baz")
D, [2023-11-10T12:45:03.071300 #169586] DEBUG -- : Cache delete: foo
=> true
```

In this example, `#write` would correctly log that the key written to
was `baz:foo` because the `namespace` option would be passed to the
`instrument` method. However, other methods like `#delete` would log
that the `foo` key was deleted because the `namespace` option was _not_
passed to `instrument`.

This commit fixes the issue by making the caller responsible for passing
the correct key to `#instrument`. This allows `normalize_key` to be
removed from the log generation which both prevents the key from being
normalized a second time and removes the need to pass the full options
hash into `#instrument`.

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-11-11 12:56:39 -06:00
Jean Boussier
7ae4a5f3b5 Automatically eager load TZInfo
On the first call it can be a bit slow because it needs to load
a bunch of data. It's also better to do it as part of boot
so that some of that data is shared via Copy-on-Write
2023-11-09 18:44:27 +01:00
fatkodima
096201f87d Fix RedisCacheStore#write_multi with :expires_in 2023-11-08 23:27:57 +02:00
John Hawthorn
42ad4d6b0b Eager load ActiveSupport::Callback procs
Follow up to previous commit where these procs were allows to be shared
between subclasses. This change allocates the procs as they are first
declared.
2023-11-07 16:19:00 -08:00
Jean Boussier
d36eb23976 Specialize various #present? implementations
Because `#present?` always resolve to `Object#present?`, it's
an extremely polymorphic method, and inline cache hits are low.

In addition, it requires an extra call to `self.blank?` which is
an overhead.

By specializing `present?` on common types, we avoid both of these
slow-downs:

```

ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
Warming up --------------------------------------
            present?   198.028k i/100ms
        opt_present?   565.521k i/100ms
Calculating -------------------------------------
            present?      2.087M (± 8.8%) i/s -     10.297M in   5.028398s
        opt_present?      5.584M (± 8.6%) i/s -     27.711M in   5.023852s

Comparison:
            present?:  2086621.6 i/s
        opt_present?:  5584373.5 i/s - 2.68x  faster
```

```
ruby 3.2.2 (2023-03-30 revision e51014f9c0) +YJIT [arm64-darwin22]
Warming up --------------------------------------
            present?   819.792k i/100ms
        opt_present?     1.047M i/100ms
Calculating -------------------------------------
            present?     12.192M (± 8.8%) i/s -     60.665M in   5.050622s
        opt_present?     16.540M (± 8.2%) i/s -     82.676M in   5.059029s

Comparison:
            present?: 12192047.5 i/s
        opt_present?: 16539689.6 i/s - 1.36x  faster
```

```ruby

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'benchmark-ips'
  gem 'activesupport'
end

require 'active_support/all'

class Object
  def opt_present?
    respond_to?(:empty?) ? !empty? : !!self
  end
end

class NilClass
  def opt_present?
    false
  end
end

class FalseClass
  def opt_present?
    false
  end
end

class TrueClass
  def opt_present?
    true
  end
end

class Array
  def opt_present?
    !empty?
  end
end

class Hash
  def opt_present?
    !empty?
  end
end

class Symbol
  def opt_present?
    !empty?
  end
end

class String
  def opt_present?
    !blank?
  end
end

class Numeric # :nodoc:
  def opt_present?
    true
  end
end

class Time # :nodoc:
  def opt_present?
    true
  end
end

array = []
hash = {}
time = Time.now

puts RUBY_DESCRIPTION
Benchmark.ips do |x|
  x.report("present?") do
    true.present?
    false.present?
    1.present?
    1.0.present?
    array.present?
    hash.present?
    :foo.present?
    time.present?
  end

  x.report("opt_present?") do
    true.opt_present?
    false.opt_present?
    1.opt_present?
    1.0.opt_present?
    array.opt_present?
    hash.opt_present?
    :foo.opt_present?
    time.opt_present?
  end

  x.compare!(order: :baseline)
end
```
2023-11-04 08:45:51 +01:00
Jean Boussier
9ade3f9b56
Merge pull request #49669 from intrip/fix-message-metadata-non-str
Fix decoding data encoded using a non-String purpose
2023-11-01 11:22:36 +01:00
Jean Boussier
db92ea32e0 Simplify attr_internal_define
The `@` prefix is always stripped, so might as well not require it.

For backward compatibility reasons we still handle the prefix for now,
but we eagerly strip it and emit a deprecation.
2023-10-31 13:42:57 +01:00
Petrik de Heus
89b0a8cb24
Merge pull request #49653 from Earlopain/add_filter-example
Better example for backtrace filter add_filter
2023-10-30 22:14:21 +01:00
Jonathan Hefner
1b195b30bc
Merge pull request #48482 from pcreux/improve-assert_changes-error-messages
Improve error messages of `assert_changes` and `assert_no_changes`
2023-10-30 13:43:51 -05:00
Philippe Creux
2b3a002a2a Improve error messages of assert_changes and assert_no_changes 2023-10-30 13:30:33 -05:00
Aashish Saini
d8b3c557e9 Use cannonical form of library names 2023-10-30 12:51:35 -05:00
John Hawthorn
b897b4c164
Merge pull request #49784 from jhawthorn/notification_exception_groups
Fix exception guards on multiple subscriber types
2023-10-30 08:25:11 -07:00
Jonathan Hefner
bb17d787c8 Ensure {down,up}case_first returns non-frozen string
Prior to this commit, `String#downcase_first` and `String#upcase_first`
would return a frozen string when called on an empty string:

  ```ruby
  # BEFORE
  "foo".downcase_first.frozen? # => false
  "".downcase_first.frozen?    # => true

  # AFTER
  "foo".downcase_first.frozen? # => false
  "".downcase_first.frozen?    # => false
  ```
2023-10-29 12:28:06 -05:00
Jean Boussier
c28e4f2434 Use double quotes more consistenly in doc and error messages
For better or worse, the Rails guide settled on double quotes
and a large part of the community also use rubocop which enforce
them by default.

So we might as well try to follow that style when providing code
snippets in the documentation or error messages.

Fix: https://github.com/rails/rails/issues/49822

I certainly didn't get them all, but consistency should be significantly
improved.
2023-10-28 11:38:49 +02:00
Jean Boussier
81ee4054da
Merge pull request #49776 from skipkayhil/hm-symbol-blank
Add Symbol#blank? to skip respond_to?(:empty?)
2023-10-28 11:02:51 +02:00
Jean Boussier
cb09616b94 Avoid exposing ActiveSupport::Testing::NoSkip
It's only meant for Rails internal use.
2023-10-27 09:03:30 +02:00
Jonathan Hefner
835d88bab9 Use h2 headings for Module::Concerning [ci-skip]
For SEO purposes, there should only be one `<h1>` per page, and the edge
version of SDoc will provide one using the module name if none are
present in documentation.
2023-10-26 17:37:32 -05:00
HolyWalley
f455d5be03 [Fix #49796] Prevent global cache options being overwritten
The reason of removing dup 5 years ago in 6da99b4e99 was to decrease memory allocations, so, it makes sense to only dup options when we know they will be overwritten.
2023-10-26 13:58:40 -05:00
Jonathan Hefner
87609e821b
Merge pull request #49791 from Earlopain/number-human-size-negative
Handle negative numbers in `NumberToHumanSizeConverter`
2023-10-26 11:20:59 -05:00
Earlopain
c6dcb11691
Handle negative numbers in NumberToHumanSizeConverter 2023-10-26 18:07:15 +02:00
Jean Boussier
9497f47131 Turn skips into errors on Rails CI
We had a few cases of tests being skipped accidentally on CI
hence not bein ran for a long time.

Skipping make sense when running the test suite locally, e.g.
you may not have Redis or some other dependency running.

But on CI, a test not being ran should be considered an error.
2023-10-26 12:46:01 +02:00
John Hawthorn
7beaacce51 Fix exception guards on multiple subscriber types
Previously in https://github.com/rails/rails/pull/43282, which shipped
with Rails 7.0, we added the guarantee that if an exception occurred
within an ActiveSupport::Notificaitons subscriber that the remaining
subscribers would still be run.

This was broken in https://github.com/rails/rails/pull/44469, where the
different types of subscribers were broken into groups by type for
performance. Although we would guard exceptions and allways run all (or
none) of the same group, that didn't work cross-group with different
types of subscriber.
2023-10-25 13:55:13 -07:00
Hartley McGuire
2dd3164c8c
Add Symbol#blank? to skip respond_to?(:empty?)
Any classes that don't implement #blank? will fall back to Object's
implementation, which checks whether #empty? is defined before either
using #empty? or implicit truthiness. Since checking whether #empty? is
defined is expensive, some core classes (Array/Hash) alias #blank?
directly to #empty? to skip the respond_to? check.

This commit applies the alias optimization to Symbol. #blank? is called
on Symbols for many Active Record query methods (select, includes,
group, order, joins, etc.) so it seems reasonable to define the #blank?
alias on Symbol as well.
2023-10-24 23:20:30 -04:00
Matt Brictson
ac4c4c40a3
Fix Object.with test class name typo
`with_test.rb` should define a class named `WithTest`. Instead, it
redefines `BlankTest`. This seems to be a copy/paste typo.

This commit renames `BlankTest` to `WithTest` to follow convention, and
to avoid any potential conflicts of 2 test files defining the same
class.
2023-10-24 07:51:40 -07:00
Andrew Novoselac
c14b98c28a Fix BroadcastLogger#dup so that it duplicates the logger's broadcasts. 2023-10-23 18:12:28 -04:00
John Hawthorn
08473e3898
Merge pull request #49728 from jhawthorn/callbacks_sharing
Reduce memory used by ActiveSupport::Callbacks
2023-10-22 20:03:55 -07:00
yuuji.yaginuma
bbe591d8f4 Don't use deprecated #to_default_s in Date#to_fs
In Rails 7.1.1, using `Date#to_fs` with an un-exist format, shows the
deprecation warning like the following.

```ruby
Date.current.to_fs(:doesnt_exist)
=> DEPRECATION WARNING: to_default_s is deprecated and will be removed from Rails 7.2 (use to_s instead) (called from <main> at ./bin/rails:4)
```

But other date-time-related classes still allow to use this.

6f6c211f47/activesupport/lib/active_support/core_ext/time/conversions.rb (L57)
6f6c211f47/activesupport/lib/active_support/core_ext/date_time/conversions.rb (L39)

So I thought this was just a typo and fixed to use `#to_s` like
other classes.
2023-10-22 17:17:42 +09:00
John Hawthorn
578cdf8004 Avoid empty Arrays in ActiveSupport::Callbacks
ActiveSupport::Callbacks often ended up with empty Arrays: on callbacks
without a conditional, and on callback sequences which had no before
and/or after callbacks.
2023-10-21 06:51:03 -07:00
John Hawthorn
6c5a042824 Reduce memory used by ActiveSupport::Callbacks
Previously, callbacks which were shared with subclasses would not share
between them the procs generated in Filters::Before and Filters::After.
This was also lazily generated so would cause memory growth after an
application is booted (and not sharable between workers via CoW).

This was because we would rebuild the objects used to invoke the
callbacks via CallbackChain#compile, so any difference in the callback
chain would result in all of the callback procs being rebuilt.

This commit changes before and after callbacks (but not around!) to be
shared between all subclasses of where it was defined. This is done by
changing Filters::Before and Filters::After to plain classes which
respond to call instead of generating procs (which wasn't strictly
necessary but was easier to implement, and also results in simpler
objects which use less memory). These objects avoid referencing and tied
to a specific callback sequence and so can be memoized and reused.

This has the most impact on applications with many Controllers, and many
callbacks in the ApplicationController (or similar).

I also took this opportunity to merge together all the different forms
of procs generated (halting, halting_and_conditional, conditional,
simple) into one form with if statements. There isn't any significant
performance benefit from the specialization previously being done.
2023-10-20 18:02:33 -07:00
Rafael Mendonça França
7c58911bd8
Merge pull request #49721 from andrewn617/dont-overwrite-broadcast-loggers-broadcast-level-in-bootstrap-rb
Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`
2023-10-20 12:59:24 -04:00
Andrew Novoselac
f212fb8b83 Fix issue where bootstrap.rb overwrites the level of a BroadcastLogger's broadcasts.
In `bootstrap.rb` we set the `Rails.logger.level` to `config.log_level`. But at this point, we may have already set up a `BroadcastLogger` with multiple broadcasts that have different levels. So, calling `level=` on the `BroadcastLogger` will overwrite the level of the individual broadcasts. So instead, let's only set the `Rails.logger.level` if the logger is not a `BroadcastLogger`.
2023-10-20 10:37:54 -04:00
Jean Boussier
f11c6ac45c
Merge pull request #49716 from Shopify/invalid-compressed-cache-entries
Handle outdated Marshal payloads in Cache::Entry with 6.1 cache_format
2023-10-20 15:59:25 +02:00
Ryuta Kamizono
10d880dcd2
Merge pull request #49718 from fatkodima/fix-ordered_options-nested-dig
Fix `OrderedOptions#dig` for array indexes
2023-10-20 19:57:22 +09:00
fatkodima
1b211421cd Fix OrderedOptions#dig for array indexes 2023-10-20 13:44:33 +03:00
Jean Boussier
a6be798e5c Handle outdated Marshal payloads in Cache::Entry with 6.1 cache_format
Ref: https://github.com/rails/rails/issues/48611
Followup: https://github.com/rails/rails/pull/48663

It's the same logic than https://github.com/rails/rails/pull/48663
but now works for the 6.1 cache format.
2023-10-20 10:21:39 +02:00
fatkodima
7fd26579c0 Fix time travel helpers to work when nested using with separate classes 2023-10-20 02:46:42 +03:00
Jonathan Hefner
9f6b721b1d
Merge pull request #49694 from fatkodima/fix-file_store-key-splitting
Fix file cache store `delete_matched` to work on keys longer than allowed filename size
2023-10-19 13:48:01 -05:00
fatkodima
9e9fe7f391 Fix file cache store to split url-encoded keys on encode-sequence boundaries
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2023-10-19 21:33:02 +03:00
Jean Boussier
bcdeea5da7 Drop dependency on mutex_m
It used to be stdlib but is being extracted in modern rubies.

Overall its usefulness is dubious. In all cases it is included in
Rails, it's only for the `synchronize` method, but end up exposing
a dozen other useless methods.

In the end just using a Mutex is clearer and simpler.

In some cases we can even get away with a single mutex in a constant.
2023-10-18 14:27:26 +02:00