Vannak a Drupalnak amolyan rejtett dolgai, az ember ritkán találkozik velük, sőt, esetleg nem is tudjuk, hogy létezik. Na egy ilyet szedek elő, bevallom, én is ma találkoztam vele először. Ez pedig a locking system, magyarul talán zárolási rendszer a randa szó rá, de becézhetjük szemafornak is.
De mit is csinál ez? Vannak a drupalban olyan folyamatok, amikből nem árt, hogyha nem indul el ugyanazon paraméterekkel kettő. Tipikusan ilyen drupal folyamat a cron, illetve a batch.
Biztosan találkoztál már olyannal a naplóban, hogy "Attempting to re-run cron while it is already running.", magyarul ilyesmi, hogy a "Cron futása nem lehetséges, mert már fut".
Ilyenkor az történik, hogy a hogy amikor elindul egy cron folyamat, egy zárolási rekord keletkezik a semaphore táblában. Ez a lock_acquire($name) függvány hívására történik. Amikor cron futás közben újabb cron indul, történik egy ellenőrzés, hogy a 'cron' nevű zárolás létezik-e már, és ha igen, akkor nem indul el az újabb cron, illetve akkor keletkezik a naplóban az emlegetett bejegyzés.
A lock státuszát mi is lekérdezhetjük: lock_may_be_available('cron').
Amikor az első cron véget ért, akkor történik a zárolás feloldása a lock_release('cron') függvény hívásával.
Mire jó ez még a gyakorlatban?
Nem néztem meg, de például a views is igen valószínű, hogy ez alapján zárolja a nézetek szerkesztési felületét. Ilyenkor van az, hogy "A nézet nem szerkeszthető, mert egy másik felhasználó zárolta", vagy valami ilyesmi..
Van egy éppen aktuális téma a drupal.hu-n, a kolléga egy másik adatbázist írna drupal felületen keresztül. Nos, én bizony preventív nem biztos, hogy szívesen hagynám, hogy egyszerre többen ugyanazt a rekordot szerkesszék. Tehát a szerkesztő form generálása során csinálnék egy lock_acquire("mylock_$recordid"); -t, a form beküldése után pedig lock_release("mylock_$recordid").
És aminek a kapcsán én találkoztam ma a locking system-el, az a boost modul. Észrevettem, hogy ha kell, ha nem, törlődnek a boost által létrehozott oldalak minden cron futáskor. Ennek az oka pedig a locking system "nem ismerete" volt. A modul fejlesztője egy egészen más vonalon oldotta meg a dolgot, ami sok esetben nem működik.
Az eset másik tanulsága: Hogy sokféleképpen meg lehet oldani egy feladatot, de ha azt nem "drupalosan" teszed, akkor bizony érhetnek meglepetések.
Hozzászólások
Király a leírás, egy apró
Király a leírás, egy apró pontosítást tennék hozzá:
A lock_acquire ami megpróbál zárolni, és ha sikerül akkor true, ha nem akkor false értékkel tér vissza. Fontos tudni, hogy 1 azaz egy atomi(megszakíthatatlan) műveletnek kell lennia a szemafor művletnek, különben nem ér egy fabadkát sem az egész rendszered. Ha először ellenőrzöd, majd lefoglalod, de utána nem ellenőrzöd, hogy sikeres volt-e a foglalás ugyan ott vagy ahol a part szakad. Lásd a cron megvalósítását:
http://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_c...
Javasolnám a lock_may_be_available() függvény használatának kerülését. Látható módon az available-t senki nem hívja a lock rendszeren kívülről:
http://api.drupal.org/api/drupal/includes%21lock.inc/function/lock_may_b...
pp
Az atomi művelet résszel
Az atomi művelet résszel egyetéretek, az is érthető, hogy a core-ban nincsen használva, de egy legitim példa:
Neki csak arra van szüksége, hogy lekérdezze, hogy fut-e a cron, de ha nem, nem fogja a szemafort bekapcsolni.
Boostnál a folyamat:
Adott egy boost_flush_cache(), és adott egy változó, amivel azt állítjuk, hogy a cron futásakor töröljük-e a boost cache-t, vagy nem. A cron folyamata során a _flush_cache hook meghívódik, és ezért a boost-nak ellenőriznie kell, hogy épp van-e bekapcsolt cron szemafor.
Viszont, hogyha cache_clear_all során hívjuk meg a és lock_aquire-t használunk a cron ellenőrzésre, akkor minden flush_cache-kor lefoglalunk egy cron lockot, és ráadásul sehol nem oldjuk fel.
Hozzászólás