Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory lock in performcheckout seems redundant #2476

Open
project-concerto opened this issue Jan 19, 2021 · 0 comments
Open

Memory lock in performcheckout seems redundant #2476

project-concerto opened this issue Jan 19, 2021 · 0 comments

Comments

@project-concerto
Copy link

Problem

The memory lock in CheckoutServiceImpl#performCheckout seems redundant, because lock used in CartStateFilter already prevent concurrent checkout.

Detail Description

performCheckout (Memory based lock)

Lock used in CheckoutServiceImpl#performCheckout exists in memory. It is used to prevent concurrent checkout for a same order. Before a checkout request is processed, it will acquire a lock from memory and release it after process. Once the lock can not be acquired, then the process will terminate, as show below.

protected static ConcurrentMap<Long, Object> lockMap = new ConcurrentHashMap<>();

public CheckoutResponse performCheckout(Order order) throws CheckoutException{
    Object lockObject = lockMap.putIfAbsent(order.Id, new Object());
    if(lockObject != null){
        // orderId exists in lockMap
        throw new CheckoutException("this order is already in process of being submitted");
    }
    if(hasOrderBeenCompleted(order)){
        throw new CheckoutException("order has been submitted");
    }
    try{
        // do checkout
    }
    ...
    finally{[CheckoutServiceImpl#performCheckout]()
}

CartStateFilter (Database based lock)

Lock used in CartStateFilter is based on database. Every POST requests that try to modify order (including add cart, apply offer code, and checkout), must acquire a lock on the order first.The detail logic to determine whether a request need to acquire lock for order is in CartStateFilter#requestRequiresLock.
This lock is implemented through accessing a table named BLC_ORDER_LOCK as shown below:

begin # acquire lock
select # if there is no record, then create with INSERT 
  count(*) 
from 
  BLC_ORDER_LOCK 
where 
  ORDER_ID = 88 
  and LOCK_KEY = '1a924f96-f039-4b48-ab5d-63ca7124a4ba' 

update # no rows affected means acquire lock failed 
  BLC_ORDER_LOCK 
set 
  LOCKED = 'Y', 
  LAST_UPDATED = 1604653067663 
where 
  ORDER_ID = 88 
  and (
    LOCKED = 'N' 
    or LAST_UPDATED <-1
  ) 
  and LOCK_KEY = '1a924f96-f039-4b48-ab5d-63ca7124a4ba'
commit

... # process request

begin # release lock
update BLC_ORDER_LOCK set LOCKED='N' where ORDER_ID=88 and LOCK_KEY='1a924f96-f039-4b48-ab5d-63ca7124a4ba'
commit

This lock based on database is able to prevent concurrent modification for the same order, which including checkout. Therefore, memory lock used in CheckoutServiceImpl#performCheckout is redundant

Suggestion

Maybe memory lock in CheckoutServiceImpl#performCheckout can be removed to obtain better performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant