Opened 2 years ago

Last modified 6 days ago

#23326 new Bug

DatabaseCache must implement incr to guarantee atomic increment

Reported by: vinayan3 Owned by:
Component: Core (Cache system) Version: 1.6
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no


django.core.cache.backends.db.DatabaseCache uses BasesCache's incr which does a get followed by a set. If the application uses multiple servers the increments will get clobbered. Furthermore, the current implementation overwrites the expiry time of a key to the default value instead of using the value which was initially set.

Change History (6)

comment:1 Changed 2 years ago by freakboy3742

  • Easy pickings set
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

You are correct that the implementation of incr on the DB cache backend will be subject to race conditions, so we should fix that.

However, I'd also say that if you're using the database cache backend for a count where there is heavy traffic, You're Doing It Wrong(TM). You should be using Redis, or at least Memcached.

comment:2 Changed 2 years ago by timgraham

  • Easy pickings unset

comment:3 Changed 2 years ago by vinayan3

I am not doing it wrong necessarily because our DB is very small with a limited number of users. The table should basically live in InnoDB's buffer pool. It's not unreasonable to just use the DB as a cache for values.

comment:4 Changed 22 months ago by manfre

  • Has patch set
  • Owner changed from nobody to manfre
  • Status changed from new to assigned

comment:5 Changed 21 months ago by manfre

  • Patch needs improvement set

My initial patch and pull request will not work as desired. Wrapping the get/set in an atomic block will only work for database isolation levels higher than Postgresql's default. There are two possible ways of ensuring an atomic incr, (1) control the locking from python, or (2) use select_for_update. Select_for_update would be the ideal solution, except DatabaseCache doesn't use the ORM and would need to expose an API for each database backend to provide SQL.

comment:6 Changed 6 days ago by timgraham

  • Owner manfre deleted
  • Status changed from assigned to new
Note: See TracTickets for help on using tickets.
Back to Top