From f2c34c93d05c55003614511b28d465b9bdc81016 Mon Sep 17 00:00:00 2001 From: Brian Stafford Date: Fri, 28 Jul 2023 06:43:50 -0500 Subject: [PATCH] dont call RecordCancel under the bookMtx --- server/market/market.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/server/market/market.go b/server/market/market.go index 9fd4b48690..266111d995 100644 --- a/server/market/market.go +++ b/server/market/market.go @@ -2380,6 +2380,16 @@ func (m *Market) processReadyEpoch(epoch *readyEpoch, notifyChan chan<- *updateS cSum := epoch.cSum misses := epoch.misses + // We can't call RecordCancel under the bookMtx since it can potentially + // trigger a user suspension and unbooking via UnbookUserOrders, which locks + // the bookMtx. So we'll track the info necessary to call RecordCancel and + // call them after the matches loop. + type cancelMatch struct { + co *order.CancelOrder + loEpoch int64 + } + var cancels = make([]cancelMatch, 0) + // Perform order matching using the preimages to shuffle the queue. m.bookMtx.Lock() // allow a coherent view of book orders with (*Market).Book matchTime := time.Now() // considered as the time at which matched cancel orders are executed @@ -2397,9 +2407,10 @@ func (m *Market) processReadyEpoch(epoch *readyEpoch, notifyChan chan<- *updateS // Update order settling amounts. for _, match := range ms.Matches() { if co, ok := match.Taker.(*order.CancelOrder); ok { - epochGap := int32((co.ServerTime.UnixMilli() / epochDur) - (match.Maker.ServerTime.UnixMilli() / epochDur)) - m.auth.RecordCancel(co.User(), co.ID(), co.TargetOrderID, epochGap, matchTime) - canceled = append(canceled, co.TargetOrderID) + cancels = append(cancels, cancelMatch{ + co: co, + loEpoch: match.Maker.ServerTime.UnixMilli() / epochDur, + }) continue } m.settling[match.Taker.ID()] += match.Quantity @@ -2413,6 +2424,13 @@ func (m *Market) processReadyEpoch(epoch *readyEpoch, notifyChan chan<- *updateS } m.bookMtx.Unlock() + for _, c := range cancels { + co, loEpoch := c.co, c.loEpoch + epochGap := int32((co.ServerTime.UnixMilli() / epochDur) - loEpoch) + m.auth.RecordCancel(co.User(), co.ID(), co.TargetOrderID, epochGap, matchTime) + canceled = append(canceled, co.TargetOrderID) + } + if len(ordersRevealed) > 0 { log.Infof("Matching complete for market %v epoch %d:"+ " %d matches (%d partial fills), %d completed OK (not booked),"+