Thanks for the reminder, Richard.

Wanted to ping folks that I've submitted a PR adding first and last IDs to
cache versions:
https://github.com/rails/rails/pull/37724

(My reasoning for using bounding IDs over a checksum is contained in the
summary, but I wanted to restate my gratitude for others' input.)

I greatly appreciate further review!



On Tue, Nov 5, 2019 at 11:38 AM richard schneeman <
richard.schnee...@gmail.com> wrote:

> Love this passion and energy. Can you all move the conversation over to
> the issue so that it's easier for other people have a similar problem to
> find or chime in?
>
> On Tue, Nov 5, 2019 at 8:16 AM Aaron Lipman <alipma...@gmail.com> wrote:
>
>> Again, good point. There are some workarounds (
>> https://evrim.io/invalidating-caches-when-using-many-to-many-associations-in-rails/),
>> but the absence of a touch: true option on has_many relations makes the
>> last ID approach less optimal.
>>
>> Also, I'm noting that support for the LAST_VERSION function didn't get
>> added to SQLite3 until version 3.25.0 (2018). As much as I liked the idea
>> of the last ID approach, I'm not seeing a clean way to implement that
>> doesn't require Rails devs to update their development environment.
>>
>> I'm going to continue to pursue a hash-based approach. Thanks again for
>> your insights, Daniel!
>>
>> On Mon, Nov 4, 2019 at 5:58 PM Daniel <dan...@heath.cc> wrote:
>>
>>> The last ID isn't stable if you replace an item within the collection
>>> though, right (assuming it's via a HABTM, so the associated record doesn't
>>> get touched)?
>>>
>>>
>>> On 11/5/19 2:21 AM, Aaron Lipman wrote:
>>>
>>> Been thinking on this a few days, here are a couple potential solutions
>>> I've been considering:
>>>
>>> Hash-based: Sum the MD5 hashes of the IDs and append the last 32
>>> hexadecimal digits of the sum to the cache version. Alternatively, use a
>>> mathematical hashing function like Fibonacci Hashing
>>> <https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/>.
>>> (The second approach wouldn't accommodate non-numeric ID columns, but may
>>> be easier to implement across various SQL flavors without any conditional
>>> logic.) Both approaches need to account for the various 64-bit limits found
>>> in MySQL and Postgres, e.g. MySQL's CONV() function.
>>>
>>> Last ID based: It occurs to me that when a record within a collection is
>>> destroyed, either the size of the collection or the ID of its last item
>>> will change. If we can reliably get that last ID, we can use it in
>>> conjunction with collection size to generate more robust cache keys. The
>>> LAST_VALUE sql function might provide this. However, MySQL didn't add
>>> LAST_VALUE until version 8 (2018), but I think we can emulate the same
>>> functionality via MySQL session variables.
>>>
>>> I'm leaning towards the "Last ID" path. I think it's a little more
>>> elegant and probably more efficient than calculating a sum when it comes to
>>> really large collections. Starting work on a pull request, but welcome
>>> other ideas/directions/considerations.
>>>
>>>
>>> On Wed, Oct 30, 2019 at 6:19 PM Daniel Heath <dan...@heath.cc>
>>> <dan...@heath.cc> wrote:
>>>
>>>> I think it’s worth considering  implementing per database, as the major
>>>> ones all have something that’ll work and the keys don’t need to be stable
>>>> across different data store implementations.
>>>>
>>>> Thanks,
>>>> Daniel Heath
>>>>
>>>> On 31 Oct 2019, at 6:17 am, Aaron Lipman <alipma...@gmail.com> wrote:
>>>>
>>>> 
>>>> Thanks for the flag, Daniel. On my first read of the code, I didn't
>>>> catch that an aggregate query was used to determine the max updated_at
>>>> timestamp (without fetching individual records) if a relation wasn't
>>>> loaded.
>>>>
>>>> Figuring out a database-side hashing function that works with all the
>>>> flavors of SQL supported by Rails may prove tricky. I'm going to consider
>>>> this some more, but an alternative approach might be to update the
>>>> documentation to acknowledge this issue and explain how to customize a
>>>> model's cache_version method according to one's needs.
>>>>
>>>> On Mon, Oct 28, 2019 at 4:31 PM Daniel Heath <dan...@heath.cc>
>>>> <dan...@heath.cc> wrote:
>>>>
>>>>> The full collection could be millions of records. Fetching the ids to
>>>>> hash might not be an option either, unless they can be hashed on the
>>>>> database side.
>>>>>
>>>>> Thanks,
>>>>> Daniel Heath
>>>>>
>>>>> On 29 Oct 2019, at 4:22 am, Aaron Lipman <alipma...@gmail.com> wrote:
>>>>>
>>>>> 
>>>>> Hi Marc & Richard,
>>>>>
>>>>> I'd categorize this as a bug. When generating a cache_version for a
>>>>> collection, one solution might be to include a hash of the IDs of all 
>>>>> items
>>>>> in the collection. This way, the cache_version will change should an item
>>>>> be removed.
>>>>>
>>>>> I believe modifying the compute_cache_version method defined in
>>>>> activerecord/lib/active_record/relation.rb
>>>>> <https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb>
>>>>> is the way to go about this.
>>>>>
>>>>> Marc, please let me know if you intend to submit a pull request. While
>>>>> I'm not on the Rails team, I'd be happy to offer any assistance and lobby
>>>>> for implementing a fix. (If you're not interested in submitting a PR, I'd
>>>>> be excited to pick this up myself.)
>>>>>
>>>>> On Sun, Oct 27, 2019 at 10:41 AM Marc Köhlbrugge <
>>>>> marckohlbru...@gmail.com> wrote:
>>>>>
>>>>>> 👍 https://github.com/rails/rails/issues/37555
>>>>>>
>>>>>> I did find a few similar issues, but they all got marked as stale
>>>>>>
>>>>>> https://github.com/rails/rails/issues/34408
>>>>>> https://github.com/rails/rails/issues/31996
>>>>>> https://github.com/rails/rails/issues/34093
>>>>>>
>>>>>> I'm surprised this doesn't appear to be a bigger problem. Perhaps I'm
>>>>>> not supposed to fragment cache my paginated results. Using collection
>>>>>> caching (`render collection: @posts, cached: true`) might be performant
>>>>>> enough.
>>>>>>
>>>>>> On Sunday, October 27, 2019 at 2:55:18 PM UTC+1, richard schneeman
>>>>>> wrote:
>>>>>>>
>>>>>>> Sounds like a bug. Can you move into an issue?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Oct 24, 2019 at 7:52 PM Marc Köhlbrugge <
>>>>>>> h...@marckohlbrugge.com> wrote:
>>>>>>>
>>>>>>>> I'm running into a problem when using fragment caching with active
>>>>>>>> record collections.
>>>>>>>>
>>>>>>>> Rails 6 uses a combination of collection.cache_key and
>>>>>>>> collection.cache_version to determine whether a fragment cache is 
>>>>>>>> fresh or
>>>>>>>> not. However, there is a scenario where the collection might change 
>>>>>>>> while
>>>>>>>> collection.cache_key and collection.cache_version stay the same.
>>>>>>>>
>>>>>>>> It happens when you use a limit on the collection and then destroy
>>>>>>>> one of those records, as long as it's not the most recent one. This way
>>>>>>>> collection.cache_key will stay the same, because the query does not 
>>>>>>>> change.
>>>>>>>> And collection.cache_version will stay the same as well, because the
>>>>>>>> collection count will remain unchanged as does the maximum updated_at
>>>>>>>> timestamp of the most recent record.
>>>>>>>>
>>>>>>>> I've build a sample app for demonstration purposes:
>>>>>>>>
>>>>>>>> https://github.com/marckohlbrugge/rails-6-collection-caching-bug
>>>>>>>>
>>>>>>>> The readme describes a way to reproduce the issue via the website
>>>>>>>> itself, or the Rails console.
>>>>>>>>
>>>>>>>> Would this be considered a bug or expected behavior? Are there any
>>>>>>>> known work arounds?
>>>>>>>> --
>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>> Groups "Ruby on Rails: Core" group.
>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>> send an email to rubyonra...@googlegroups.com.
>>>>>>>> To view this discussion on the web visit
>>>>>>>> https://groups.google.com/d/msgid/rubyonrails-core/4cc0ae69-c736-48d0-bd84-8b3f44dc879d%40googlegroups.com
>>>>>>>> <https://groups.google.com/d/msgid/rubyonrails-core/4cc0ae69-c736-48d0-bd84-8b3f44dc879d%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>> .
>>>>>>>>
>>>>>>> --
>>>>>>> Richard Schneeman
>>>>>>> https://www.schneems.com
>>>>>>>
>>>>>> --
>>>>>> You received this message because you are subscribed to the Google
>>>>>> Groups "Ruby on Rails: Core" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>> send an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>>>>> To view this discussion on the web visit
>>>>>> https://groups.google.com/d/msgid/rubyonrails-core/6590103e-3528-4896-bc07-e6ff6a194bef%40googlegroups.com
>>>>>> <https://groups.google.com/d/msgid/rubyonrails-core/6590103e-3528-4896-bc07-e6ff6a194bef%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>>
>>>>> --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "Ruby on Rails: Core" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>>>> To view this discussion on the web visit
>>>>> https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43iCipyOZddZAT1WCrtQ7g7VRLeokgLRGcYroK-TvGoGWw%40mail.gmail.com
>>>>> <https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43iCipyOZddZAT1WCrtQ7g7VRLeokgLRGcYroK-TvGoGWw%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>>> --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "Ruby on Rails: Core" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>>>> To view this discussion on the web visit
>>>>> https://groups.google.com/d/msgid/rubyonrails-core/4A85F762-275C-4796-9A47-0586833DADFA%40heath.cc
>>>>> <https://groups.google.com/d/msgid/rubyonrails-core/4A85F762-275C-4796-9A47-0586833DADFA%40heath.cc?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Ruby on Rails: Core" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43h%2BOsd6b_1H2a%3DGScC8dpp%3DMw9d1mO0id6Fdjy2igASUg%40mail.gmail.com
>>>> <https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43h%2BOsd6b_1H2a%3DGScC8dpp%3DMw9d1mO0id6Fdjy2igASUg%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Ruby on Rails: Core" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/rubyonrails-core/FD13AF4B-ADBA-4ABC-9F56-D63F181B653D%40heath.cc
>>>> <https://groups.google.com/d/msgid/rubyonrails-core/FD13AF4B-ADBA-4ABC-9F56-D63F181B653D%40heath.cc?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Ruby on Rails: Core" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43hUknLmyi_dWmP2TW3Uspcvw5m7jWAUO%3DiPg_u_bWJFDg%40mail.gmail.com
>>> <https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43hUknLmyi_dWmP2TW3Uspcvw5m7jWAUO%3DiPg_u_bWJFDg%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Ruby on Rails: Core" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to rubyonrails-core+unsubscr...@googlegroups.com.
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/rubyonrails-core/89cf81d9-d107-f976-572c-caf1a095561e%40heath.cc
>>> <https://groups.google.com/d/msgid/rubyonrails-core/89cf81d9-d107-f976-572c-caf1a095561e%40heath.cc?utm_medium=email&utm_source=footer>
>>> .
>>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Ruby on Rails: Core" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to rubyonrails-core+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43hXHE9NOeoJoHif4FFuxK1YLsAc%2BkQNiEBxckpTYjULKA%40mail.gmail.com
>> <https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43hXHE9NOeoJoHif4FFuxK1YLsAc%2BkQNiEBxckpTYjULKA%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>
>
> --
> Richard Schneeman
> https://www.schneems.com
>
> --
> You received this message because you are subscribed to the Google Groups
> "Ruby on Rails: Core" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to rubyonrails-core+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/rubyonrails-core/CAFA5uRMZjpD0QDp%2BGrWxnd3BC6OtzUiPfOMn%2B-yg_UadPSf09Q%40mail.gmail.com
> <https://groups.google.com/d/msgid/rubyonrails-core/CAFA5uRMZjpD0QDp%2BGrWxnd3BC6OtzUiPfOMn%2B-yg_UadPSf09Q%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to rubyonrails-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rubyonrails-core/CAEJZ43jdZLyw%2B%2B66joU5QfyogPm0EBW3Gp9Pmp98W4U%3Du%2Byhtg%40mail.gmail.com.

Reply via email to