I’m creating a stored procedure which can increment the value of a counter and return if that invocation was responsible for reaching the MaxValue. The tricky part is this procedure will be call quickly and in parallel from different threads and different machines.
Example scenario:
Two threads executing in parallel call the same stored procedure to increment the same counter. Lets assume CounterId = 5 is passed in as a parameter for both. Before either executes the Counter record currently has field values of CounterValue = 9 and a MaxValue = 10.
What I want to happen is for one of the procedures to successfully increment the CurrentValue to 10 and return a result indicating it was responsible for making the change which caused CounterValue to reach the MaxValue. The other procedure should not increment the value (since it would go past 10) and should return a result indicating that the MaxReach was already met for the counter.
I thought about performing a query before or after but it seems that could leave a ‘hole’ where a change could be made by separate thread and cause a false positive/negative to be returned.
This is just a start of an idea for the procedure. I feel like it needs locking, a transaction or something?
UPDATE SomeCounters
SET CounterValue = (CounterValue + @AddValue),
MaxReached = CASE WHEN MaxValue = (CurrentValue + 1) THEN 1 ELSE 0
WHERE CounterId = @CounterId
AND MaxReached = 0
Use
OUTPUTThe update is atomic and you can then select the value out of the @temp table and do whatever you want with it. This way you’ll be able to capture the exact update that caused MaxReached to be set to true (1).