Without Latching
This part of the example represents a
world without latches. Assume that the row containing the values
(2,200) in Transaction 1 arrived at the page a fraction of a second
before Transaction 2, when the values (3,300) are written. Transaction
1 writes to Slot 1, as seen in Figure 4 and Figure 5.
The update has gone through, as you have a second row in the page in slot 1 with the hex values 02 and c8 (which are the values 2 and 200, respectively). However, the page header is not yet updated. They still appear as in Figure 2. m_freedata is still 111, and the m_slotcnt value is still 1.
Before the header information is written,
Transaction 2 arrives and wants to write a row with its values (3,300).
Without a mechanism to stop it, Transaction 2 queries the m_freedata and m_slotcnt values, and writes its data into Slot 1, as seen in Figure 6 and Figure 7.
Before the “2,200” transaction could update the
metadata, the “3,300” transaction had arrived. This second transaction
checked the m_freedata field,
found the location to write the row, and made the change. By now
Transaction 1 has updated the header information, but this is also
overwritten by Transaction 2. The change made by Transaction 1 is gone,
and we have a lost update, as seen in Figure 8 and Figure 9.
This scenario reflects one of the prime uses for latches — serializing writes to prevent lost updates.
As mentioned before, you won’t be able to repeat
this demonstration. SQL Server wouldn’t let you. In order to present it
here, the output had to be massaged. Now take a look at what actually
happens in a normal, i.e., latched, scenario. This you will be able to
repeat.