Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#31728 closed Bug (fixed)

cache.backends.db._cull sometimes fails with 'NoneType' object is not subscriptable

Reported by: Guillermo Bonvehí Owned by: nobody
Component: Core (Cache system) Version: dev
Severity: Normal Keywords: cache db
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Guillermo Bonvehí)

I'm sporadically getting some cache errors using database backend.
The error is: 'NoneType' object is not subscriptable
And the backtrace:

/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py:143→ _get_response
/usr/local/lib/python3.7/site-packages/django/template/response.py:108→ render
/usr/local/lib/python3.7/site-packages/django/utils/decorators.py:156→ callback
/usr/local/lib/python3.7/site-packages/django/middleware/cache.py:103→ process_response
/usr/local/lib/python3.7/site-packages/django/utils/cache.py:374→ learn_cache_key
/usr/local/lib/python3.7/site-packages/django/core/cache/backends/db.py:104→ set
/usr/local/lib/python3.7/site-packages/django/core/cache/backends/db.py:136→ _base_set
/usr/local/lib/python3.7/site-packages/django/core/cache/backends/db.py:277→ _cull

This is using Django 2.2.11 but I see the same code is in master.

https://github.com/django/django/blob/master/django/core/cache/backends/db.py#L270

                cursor.execute(
                    connection.ops.cache_key_culling_sql() % table,
                    [cull_num])
                cursor.execute("DELETE FROM %s "
                               "WHERE cache_key < %%s" % table,
                               [cursor.fetchone()[0]])

From what I can understand, the cursor after running connection.ops.cache_key_culling_sql() command is not returning any data, so cursor.fetchone()[0] afterwards fails.
I guess a simple check to see if it contains data would be enough, may apply for an easy picking.

Edit: Wording

Change History (10)

comment:1 by Guillermo Bonvehí, 4 years ago

Description: modified (diff)

comment:3 by Guillermo Bonvehí, 4 years ago

Has patch: set

comment:4 by Simon Charette, 4 years ago

Patch needs improvement: set
Triage Stage: UnreviewedAccepted

Thanks for the report and patch. Left some comments for improvements to make the test backend agnostic, once they are addressed feel free to uncheck the _Patch needs improvement_ flag for your patch to show up in the review queue.

comment:5 by Guillermo Bonvehí, 4 years ago

Patch needs improvement: unset

Thanks to you Simon for the review. I moved the test to the base test class, if I understood correctly that's enough for it to be backend agnostic. Let me know if there's some other change needed.

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

Resolution: fixed
Status: newclosed

In f386454d:

Fixed #31728 -- Fixed cache culling when no key is found for deletion.

DatabaseCache._cull implementation could fail if no key was found to
perform a deletion in the table. This prevented the new cache key/value
from being correctly added.

comment:7 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

In b2e2489:

[3.1.x] Fixed #31728 -- Fixed cache culling when no key is found for deletion.

DatabaseCache._cull implementation could fail if no key was found to
perform a deletion in the table. This prevented the new cache key/value
from being correctly added.

Backport of f386454d1302b66d0eb331ed0ae9e4811e2f3a15 from master

comment:8 by Guillermo Bonvehí, 4 years ago

Thanks Mariusz! One question, I'd like to backport this to 2.2.x, should I just open a new PR on Github and/or another ticket here?

in reply to:  8 comment:9 by Mariusz Felisiak, 4 years ago

Replying to Guillermo Bonvehí:

Thanks Mariusz! One question, I'd like to backport this to 2.2.x, should I just open a new PR on Github and/or another ticket here?

The issue has been present since the feature was introduced (0fa1aa8711a6e1f3653e98943f2847366c0ac556). Per our backporting policy this means it doesn't qualify for a backport to 3.0.x or 2.2.x anymore. See https://docs.djangoproject.com/en/3.0/internals/release-process/ for more details.

comment:10 by Guillermo Bonvehí, 4 years ago

Thanks for the answer.
In case anyone wants to apply to their own code, here's a PR with the changes (sorry I didn't read your answer before creating it): https://github.com/django/django/pull/13094

Note: See TracTickets for help on using tickets.
Back to Top