Opened 8 months ago

Last modified 5 months ago

#23326 assigned Bug

DatabaseCache must implement incr to guarantee atomic increment

Reported by: vinayan3 Owned by: manfre
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

Description

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 (5)

comment:1 Changed 8 months 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 8 months ago by timgraham

  • Easy pickings unset

comment:3 Changed 8 months 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 6 months ago by manfre

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

comment:5 Changed 5 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.

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