I have the following problem:
Our system has products that when released only are allowed to be purchased X times. Upon purchase a central purchasing algorithm checks how many Orders exist and if below X proceeds with the purchase.
In pseudoish C# code:
public class OrderMethods
{
public static Purchase(Product product, Client client)
{
int purchases = /* count order records of this product */;
if(purchases>=MAX_ORDERS) throw PurchaseException();
/* perform purchase by inserting order record in database */
}
}
The problem is that sometimes when there's a high demand for a certain product a lot of request happen at the same time and more than MAX_ORDERS are registered. This happens about once a year :(.
What's the best solution for solving this? I'm using ASP.NET/C#, Ling2SQL and MSSQL. We have 1000> orders per day. It's important that orders are processed in the order they are requested.
The solutions I've comeup with so far:
One global mutex?
One mutex per product stored in a hashtable with an access function like:
private Mutex GetPurchaseMutex(Guid productId) { if (mutexTbl[productId] == null) { mutexTbl[productId] = new Mutex(); } return (Mutex)mutexTbl[productId]; }
Where mutexTbl is an Hashtable. Here I haven't figure out how discard old mutexes in a nice way though.
Using a T-SQL INSERT Trigger on the Order table that checks how many orders there are:
CREATE TRIGGER Triggers_OrderInsertTrigger ON Orders AFTER INSERT AS IF /* check if there's to many orders */ BEGIN RAISERROR ('Too many orders', 16, 1); ROLLBACK TRANSACTION; RETURN END;
But I'm not so fond of either of these solutions. How would you solve this?