MainframeSupports
tip uge 35/2001:

Det er ikke altid lige let at benytte DB2 og især ikke, når man skal lave opdateringer. Så risikerer man meget hurtigt at løbe ind i situationer, hvor mange parallelle tasks vil lave de samme opdateringer. Man risikerer dels datatab (sidste mand vinder) og dels deadlock-situationer.

Forestil dig, at dit program læser en række fra en tabel, laver beregninger eller tegnmanipulation på rækken og opdater rækken med de opnåede resultater. Forestil dig nu, at et andet task samtidigt udfører det samme program og læser den samme række før det første task har udført opdateringen. Nu har du en sidste mand vinder situation og dermed potentielt datatab, især hvis det var meningen, at det andet task skulle have foretaget sine beregninger ud fra resultatet af det første task.

Dette her er selvfølgelig en kendt problemstilling i ethvert online-system og der er mange forskellige løsninger. Hvis man i den skitserede situation vil serialisere taskene, kan man man benytte følgende trick:

  1. Før SELECT af den række, der skal manipuleres med, laver du en dummy UPDATE af rækken. Se nedenfor, hvordan den skal se ud.
  2. Så laver du din SELECT.
  3. Så laver du den rigtige UPDATE.

Ideen med en dummy UPDATE udspringer af mit tip fra uge 23/1999. Fidusen er, at man kan lave en UPDATE, der ikke opdaterer noget som helst, men den tager en såkaldt X LOCK, der gør, at ingen andre kan læse eller opdatere den page, som rækken befinder sig på. De andre tasks, der udfører det samme program, vil nu vente pænt ved dummy UPDATE kaldet, da de ikke kan komme til at opdatere rækken før det første task har udført en COMMIT.

Her er et konkret eksempel:

UPDATE MYTABLE SET COLX = COLX WHERE COLA = :VARA;
SELECT COLY, COLZ INTO :VARY, :VARZ FROM MYTABLE WHERE COLA = :VARA;
VARY = ADVANCEDYFUNC(VARY);
VARZ = ADVANCEDZFUNC(VARZ);
UPDATE MYTABLE SET COLY = :VARY, COLZ = :VARZ WHERE COLA = :VARA;
COMMIT;

Den første UPDATE er en dummy UPDATE med den ønskede sideeffekt, selv om den ikke opdaterer noget som helst. Denne UPDATE er vores enqueue. Læg mærke til, at WHERE-delen i vores dummy UPDATE skal være den samme som i de efterfølgende SQL-kald. I princippet kunne man godt lave en dummy UPDATE mod en hvilken som helst række i en hvilken som helst tabel, men så risikerer man at skabe problemer helt andre steder. Det er en god ting, at dummy UPDATE'n kun rammer en enkelt række, da opdateringer mod andre rækker således kan slippe forbi (med mindre de andre rækker ligger på samme page og man ikke benytter row level locking).

Den afsluttende COMMIT er vores dequeue. Det er vigtigt at notere sig, at DB2 ikke har nogen anden enqueue/dequeue mekanisme. Man skal derfor tænke sig godt om, før man begynder at tage dette trick i brug, da en COMMIT frigiver alle låse og ikke lige dem, man synes der skal frigives. Hvis man indfører tricket midt i et større opdateringskompleks, så skal man udelade COMMIT'en i ovenstående eksempel, så den COMMIT, der naturligt afslutter opdateringskomplekset, er den der frigiver låsen.

Forrige danske tip        Last tip in english        Tip oversigten