From 3d635521ebf68c8a9fa7bd98e1bc5c85085f8ec4 Mon Sep 17 00:00:00 2001 From: Christopher Neugebauer Date: Sun, 1 May 2016 12:19:36 +1000 Subject: [PATCH] CartController now uses BatchController memoisation --- registrasion/controllers/cart.py | 69 ++++++-------------------------- 1 file changed, 13 insertions(+), 56 deletions(-) diff --git a/registrasion/controllers/cart.py b/registrasion/controllers/cart.py index 283c3119..d0a9f057 100644 --- a/registrasion/controllers/cart.py +++ b/registrasion/controllers/cart.py @@ -16,6 +16,7 @@ from registrasion.models import commerce from registrasion.models import conditions from registrasion.models import inventory +from.batch import BatchController from .category import CategoryController from .discount import DiscountController from .flag import FlagController @@ -34,10 +35,11 @@ def _modifies_cart(func): def inner(self, *a, **k): self._fail_if_cart_is_not_active() with transaction.atomic(): - with CartController.operations_batch(self.cart.user) as mark: - mark.mark = True # Marker that we've modified the cart + with BatchController.batch(self.cart.user): + # Mark the version of self in the batch cache as modified + memoised = self.for_user(self.cart.user) + memoised._modified_by_batch = True return func(self, *a, **k) - return inner @@ -47,6 +49,7 @@ class CartController(object): self.cart = cart @classmethod + @BatchController.memoise def for_user(cls, user): ''' Returns the user's current cart, or creates a new cart if there isn't one ready yet. ''' @@ -64,59 +67,6 @@ class CartController(object): ) return cls(existing) - # Marks the carts that are currently in batches - _FOR_USER = {} - _BATCH_COUNT = collections.defaultdict(int) - _MODIFIED_CARTS = set() - - class _ModificationMarker(object): - pass - - @classmethod - @contextlib.contextmanager - def operations_batch(cls, user): - ''' Marks the boundary for a batch of operations on a user's cart. - - These markers can be nested. Only on exiting the outermost marker will - a batch be ended. - - When a batch is ended, discounts are recalculated, and the cart's - revision is increased. - ''' - - if user not in cls._FOR_USER: - _ctrl = cls.for_user(user) - cls._FOR_USER[user] = (_ctrl, _ctrl.cart.id) - - ctrl, _id = cls._FOR_USER[user] - - cls._BATCH_COUNT[_id] += 1 - try: - success = False - - marker = cls._ModificationMarker() - yield marker - - if hasattr(marker, "mark"): - cls._MODIFIED_CARTS.add(_id) - - success = True - finally: - - cls._BATCH_COUNT[_id] -= 1 - - # Only end on the outermost batch marker, and only if - # it excited cleanly, and a modification occurred - modified = _id in cls._MODIFIED_CARTS - outermost = cls._BATCH_COUNT[_id] == 0 - if modified and outermost and success: - ctrl._end_batch() - cls._MODIFIED_CARTS.remove(_id) - - # Clear out the cache on the outermost operation - if outermost: - del cls._FOR_USER[user] - def _fail_if_cart_is_not_active(self): self.cart.refresh_from_db() if self.cart.status != commerce.Cart.STATUS_ACTIVE: @@ -144,6 +94,13 @@ class CartController(object): self.cart.time_last_updated = timezone.now() self.cart.reservation_duration = max(reservations) + + def end_batch(self): + ''' Calls ``_end_batch`` if a modification has been performed in the + previous batch. ''' + if hasattr(self,'_modified_by_batch'): + self._end_batch() + def _end_batch(self): ''' Performs operations that occur occur at the end of a batch of product changes/voucher applications etc.