-
 Zitat von dschroeder
Zu unserem selbstgebauten Locking: Da wird einfach in einer Locktabelle für jeden zu sperrenden Datensatz ein Eintrag mit dem Dateinamen und der Record-ID des Datensatzes erzeugt. Jedes Programm, das den Datensatz sperren möchte, guckt vorher in dieser Tabelle nach, ob der Satz bereits von einem anderen Job blockiert wurde. Das Verfahren ist simpel und funktioniert natürlich nur, wenn sich alle an dieses Verfahren halten. Ein Programm, das dieses Verfahren nicht beachtet und sich einfach auf physische Datenbanklocks verlässt, erkennt so eine "logische" Sperrung natürlich nicht.
... noch eine Bemerkung zu eurem Sperrverfahren:
Ich würde hier Satzsperren und Prozesssynchronisation gedanklich voneinander trennen. Satzsperren sind kurz andauernd (Milllisekunden) und dienen der Transaktionskontrolle, das macht die Datenbank automatisch und hier dürfen keine lang andauernden (mehar als eine Bildschirmtransaktion) Sperren auftreten.
Prozesssynchronisation benötigt lang andauernde Sperren, bis ein anderer Prozess fertig ist. Hierunter fallen z.B.: Reisebuchungen, Verwaltung von Versicherungsverträgen können dazu gehören, auch Bestellungen mit Reservierungen können dazu gehören; in dieselbe Kategorie fallen auch etliche Batchprogramme (während Verbuchung A läuft, dürfen manche Prozesse nicht laufen), insbesondere bei Parallelisierung (wg. Speed).
Euer Ansatz mit einer Datei, die Sperren verwaltet ist erst mal OK. Ich würde das allerdings optimieren.
- Sperre setzen durch schreiben eines Sperrsatzes unter commit in einer ACTGRP, die nie commited wird.
- Sperre freigeben durch löschen des Sperrsatze.
- bricht das irgendwo ab, macht die Datenbank einen automatischen Rollback (hackt jemand die Stromzufuhr durch, beim nächsten IPL)
- zentralisiert wird das in einem SRVPGM, das als einziges die Sperrdatei benutzt und dazu aufgerufen wird. Beim CRTSRVPGM ACTGRP(NOCOMMIT) verwenden.
- kann eine Sperre nicht erteilt werden, sendet die entsprechende Procedure eine Abbruchmeldung.
- optional kann man noch einen wait Parameter in die Schnittstelle aufnehmen, bei immed sendet man eine Escape Message - ansonsten blockiert man den aufrufenden Prozess (lässt ihn warten).
Die Sperrdatei wird mit recordwait immed angelegt.
D*B
-
 Zitat von BenderD
... noch eine Bemerkung zu eurem Sperrverfahren:
Ich würde hier Satzsperren und Prozesssynchronisation gedanklich voneinander trennen. Satzsperren sind kurz andauernd (Milllisekunden) und dienen der Transaktionskontrolle, das macht die Datenbank automatisch und hier dürfen keine lang andauernden (mehar als eine Bildschirmtransaktion) Sperren auftreten.
Prozesssynchronisation benötigt lang andauernde Sperren, bis ein anderer Prozess fertig ist. Hierunter fallen z.B.: Reisebuchungen, Verwaltung von Versicherungsverträgen können dazu gehören, auch Bestellungen mit Reservierungen können dazu gehören; in dieselbe Kategorie fallen auch etliche Batchprogramme (während Verbuchung A läuft, dürfen manche Prozesse nicht laufen), insbesondere bei Parallelisierung (wg. Speed).
Euer Ansatz mit einer Datei, die Sperren verwaltet ist erst mal OK. Ich würde das allerdings optimieren.
- Sperre setzen durch schreiben eines Sperrsatzes unter commit in einer ACTGRP, die nie commited wird.
- Sperre freigeben durch löschen des Sperrsatze.
- bricht das irgendwo ab, macht die Datenbank einen automatischen Rollback (hackt jemand die Stromzufuhr durch, beim nächsten IPL)
- zentralisiert wird das in einem SRVPGM, das als einziges die Sperrdatei benutzt und dazu aufgerufen wird. Beim CRTSRVPGM ACTGRP(NOCOMMIT) verwenden.
- kann eine Sperre nicht erteilt werden, sendet die entsprechende Procedure eine Abbruchmeldung.
- optional kann man noch einen wait Parameter in die Schnittstelle aufnehmen, bei immed sendet man eine Escape Message - ansonsten blockiert man den aufrufenden Prozess (lässt ihn warten).
Die Sperrdatei wird mit recordwait immed angelegt.
D*B
Guten Morgen,
unser Sperrverfahren läuft in etwa so, wie du es skizziert hast, denke ich. Der Satz in der Sperrdatei wird mit einem physischen Lock versehen. Zugegebenermaßen noch mit F-Bestimmung. Es gibt auch nur ein zentrales Tool, das die Sperren verwaltet.
-
Hallo Baldur und D*B,
ihr habt ja beide das Verfahren update table where current of cursor genannt. Ich habe dazu mal gerade etwas in der IBM-Doku gelesen. Im IBM Beispiel dazu steht:
DECLARE THISEMP CURSOR FOR
SELECT EMPNO, LASTNAME,
WORKDEPT, JOB
FROM CORPDATA.EMPLOYEE
FOR UPDATE OF JOB
Meine Frage hierzu ist: Was bedeutet "OF JOB" ? Heißt das, dass ich schon beim Deklarieren des Cursors das Feld angeben kann (oder muss?), welches ich später updaten möchte?
-
... soweit ich das im Kopf habe, ist die update clause optional.
Ich habe allerdings wieder mal eine Anmerkung: Entgegen der Empfehlung anderer Kollegen, rate ich immer zum select *, dann kann man nämlich beim fetch in die entsprechende externe DS einlesen (ein unschätzbarer Vorteil der DB2/400). Dieses Verfahren ist narrensicher zur Compilezeit, zur Laufzeit und bei Änderung. Wenn ich denn nur eine Teilauswahl haben will, erledige ich das über eine View (wozu ich ohnehin stets rate).
D*B
PS: ich habe mal beim fetch in einer ellenlangen Feldliste zwei Felder vertauscht. Der Fehler ist erst aufgefallen, als krumm geschobene Daten aufgefallen sind. Ich habe Tage gesucht und ohne Journale wäre ich halbwegs aufgeschmissen gewesen.
-
Vielen Dank,
wenn es wenige Felder sind, lesen wir normalerweise ein Feldauswahl. Bei vielen Feldern dagegen lesen wir meistens in die externe Struktur ein.
-
Das mache ich:
Am einfachsten ist ein Service, klar mit eigener geschlüsselter Tabelle.
Die Tabelle enthält einen Hauptkey, ggf. Mandant, so wie ein allgemeines großes Feld (256 reicht meist) als Sperr-Key. Zusätzlich ein Feld mit dem Job-Bezeichner und aus statistischen Gründen einen Timestamp.
Der Service läuft in einer eigenen ACTGRP mit Commit *CHG.
Der Service liefert *on/*off ob eine Sperre erhalten wurde und per Referenz eine Error-Struktur, die den sperrenden Job bezeichnet. Somit kann per "if not GetLock(Mandant : %char(k1) + ',' + %char(k2) : error)" einfach geprüft werden.
Mittels UnLock(Mandant : %char(k1) + ',' + %char(k2)) wird der Lock entfernt, wenn er dem Job gehört.
k1 + k2 sind hier Synonyme für variable Schlüsselgestaltung.
Sperrschleife wegen konkurierender Zugriffe:
Step 1:
Read und prüfen per SQL ACTIVE_JOB_INFO
- Wenn nicht vorhanden, Insert mit Schlüssel eigenem Job und Timestamp
- Wenn SQLCODE = 0, commit und return *on
- Wenn doppelter Key, iter in Schleife, anderer war schneller, erforderliche falls anderer Rollback macht.
- Wenn SQLCODE <> 0, schwerer Fehler, der nicht vorkommen sollte, rollback, return *off
Step 2:
- wenn eigener Job oder Job nicht aktiv, update Timestamp, commit return *on
- wenn Job Aktiv, commit, return *off.
Im Test auf einer P9 konnte ich ca. 1000 Locks je Sekunde damit durchführen.
Wenn Programme über Menüs aufgerufen werden, kann man entweder im Menüprogramm oder per Wrapper nach Ende des Programmes einen RemoveAllLocks() des eigenen Jobs machen.
Aus Sicherheitsgründen erstelle ich noch einen Haupt-Lock um parallele Locks auszuschliessen:
do *on;
upddate locktable set locktime = current timestamp;
wenn sqlcode = 100 => Insert
wenn sqlcode = 0 => leave
// grober Fehler
enddo;
Somit kann noch sichergestellt werden, dass für die Lockprüfung keiner dazwischen kommt.
Jedes Programm ist selber dafür verantwortlich, Locks zu setzen und zu entfernen. Auf Grund der Schlüssel kann man beliebig viele Locks setzen.
1 Mal am Tag werden alle Locks gelöscht, deren Jobs nicht mehr aktiv sind.
-
Ich hab es auch mal probiert da unser Kundenstamm hier auch mittels CHAIN-Lock den Satz sperrt.
Es funktioniert per SQL (SELECT/UPDATE) mit RS.
Da bleibt der Satz bis zum COMMIT/ROLLBACK gesperrt.
-
 Zitat von prsbrc
Ich hab es auch mal probiert da unser Kundenstamm hier auch mittels CHAIN-Lock den Satz sperrt.
Es funktioniert per SQL (SELECT/UPDATE) mit RS.
Da bleibt der Satz bis zum COMMIT/ROLLBACK gesperrt.
... das Problem dabei ist, dass die Sperre einen konkurrierenden update verhindert, aber den eigenen Update noch nicht ermöglicht. Für den update wird dann versucht, die Sperre zu eskalieren, was bei konkurrierendem Zugriff dazu führt, dass der erste Anforderer abbricht.
D*B
-
Wobei der Abbruch auch noch 1 Minute dauert.
D.h., im Dialog erfährt der User erst nach 1 Minute, dass da ein Lock besteht.
Besser ist da schon die Job-Prüfung, was ja nun auch via SQL geht.
-
 Zitat von Fuerchau
Wobei der Abbruch auch noch 1 Minute dauert.
D.h., im Dialog erfährt der User erst nach 1 Minute, dass da ein Lock besteht.
Besser ist da schon die Job-Prüfung, was ja nun auch via SQL geht.
... dass der Abbruch eine Minute dauert, liegt allerdings an den idiotischen defaults der Einstellungen der Dateien. Waitfile steht hier auf *immed und waitrcd auf 60 Sekunden, hier müssen die Jungs und Mädels bei IBM Stunden beieinander gesessen haben und intensiv an Nichts gedacht haben. Waitfile * immed führt dazu, dass das commit level serializable (das der SQL Standard als Unterlassungswert fordert) mit recor level access unvereinbar ist. Datensätze, die langer als Millisekunden dauern, werden auch in Minuten nicht frei: Der Benutzer eines schadhaften Programms hat einen Satz gelesen und ist in die Mittagspause gegangen.
Diese unsinnigen Einstellungen ließen sich korrigieren, für WAITRCD wäre 1 Sekunde angemessen und WAITFILE sollte in jedem Fall größer als WAITRCD sein. Man kann dies allerdings per OVRDBF für das jeweilige Programm anpassen. Für Dialogprogramme auf *IMMED oder die oben gennante 1 sec (wenn man sich nicht traut) und für Synchronisatiuonszwecke von Batchjobs auf *NOMAX (das ist besser als in Schleife warten und neu versuchen, spart Strom und verhindert, dass ein anderer reinrutscht).
Dein Vorschlag mit der Job-Prüfung ist m.E. nur der zweitbeste Weg; genauer (wie der Schachspieler sagen würde) ist, den zu sperrenden Satz ohne zu lesen sofort zu ändern, bzw. zu schreiben.
Der Unlock erfolgt dann durch ROLLBACK oder COMMIT und der nächste wartende Job läuft automatisch an.
D*B
PS: Bei *NOMAX Wartezeiten muss man sorgfältig auf Deadlock Vermeidung achten, was auch für Warteschleifen gilt.
-
Es gibt schon mal Transaktionen, die länger als 1 Sekunde dauern, i.d.R. aber selten länger als 20-30 Sekunden. Um den Betrieb nicht zu stören, ist eine Wartezeit weniger als 30 Sekunden nicht so empfehlenswert.
Die "Belegsperre" läuft in einer eigenen ACTGRP um eben gegen übergeordente Commits im Job gefeit zu sein.
Auch das Halten von Locks hat sich als ungünstig erwiesen, daher die Lösung mit der Job-Info, wer der Halter des logischen Locks ist.
Dadurch kann auch bei Nichterhalten des Locks eine Nachricht über den Halter ausgegeben werden. Dies ist bei regulären Locks halt nur mit Schwierigkeiten (Lock-API's) heraus zu finden.
Während der logischen Sperre eines Beleges erfolgen über einen Dialog durchaus mehrere Transaktionen was zur Folge hätte, dass die physischen Locks gelöst würden.
Meine oben beschriebene Lösung ist nun seit fast 3 Jahren erfolgreich bei einem Kunden im Einsatz und hat viele Probleme gelöst. Und sie ist unabhängig von der Satzwartezeit;-).
Similar Threads
-
By Lucky662 in forum NEWSboard Programmierung
Antworten: 11
Letzter Beitrag: 28-07-22, 09:30
-
By LoCal in forum NEWSboard Programmierung
Antworten: 1
Letzter Beitrag: 22-07-05, 11:15
-
By gize in forum NEWSboard Drucker
Antworten: 6
Letzter Beitrag: 22-02-05, 07:48
-
By Miles in forum IBM i Hauptforum
Antworten: 3
Letzter Beitrag: 13-10-03, 20:47
-
By Arbi in forum IBM i Hauptforum
Antworten: 1
Letzter Beitrag: 22-09-01, 11:13
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- You may not post attachments
- You may not edit your posts
-
Foren-Regeln
|
Erweiterte Foren Suche
Google Foren Suche
Forum & Artikel Update eMail
AS/400 / IBM i
Server Expert Gruppen
Unternehmens IT
|
Kategorien online Artikel
- Big Data, Analytics, BI, MIS
- Cloud, Social Media, Devices
- DMS, Archivierung, Druck
- ERP + Add-ons, Business Software
- Hochverfügbarkeit
- Human Resources, Personal
- IBM Announcements
- IT-Karikaturen
- Leitartikel
- Load`n`go
- Messen, Veranstaltungen
- NEWSolutions Dossiers
- Programmierung
- Security
- Software Development + Change Mgmt.
- Solutions & Provider
- Speicher – Storage
- Strategische Berichte
- Systemmanagement
- Tools, Hot-Tips
Auf dem Laufenden bleiben
|
Bookmarks