FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index All products support FLOCK() und RLOCK()
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
FLOCK() und RLOCK()
Posted: Tue Aug 26, 2025 12:10 AM

FLOCK() und RLOCK() wirken ja immer auf die Datei und nicht auf die einzelnen Workareas.

Hat jemand einen guten Vorschlag, wie man eine einfache und robuste Lösung für SafeLock() und SafeUnlock() bauen kann – idealerweise so, dass sowohl FLOCK() als auch RLOCK() sauber abgebildet werden und man im eigenen Prozess Mehrfachaufrufe erkennt und korrekt wieder freigibt?

Ich denke z. B. an so etwas in der Art (Pseudocode):

STATIC hLocks := {}

FUNCTION SafeFlock( cFile )

IF hLocks[ cFile ] == .T.

  RETURN { "success"=>.T., "alreadyLocked"=>.T. }

ENDIF

IF FLOCK()

  hLocks[ cFile ] := .T.

  RETURN { "success"=>.T., "alreadyLocked"=>.F. }

ELSEIF NETERR()

  RETURN { "success"=>.F., "error"=>"E_NET" }

ELSE

  RETURN { "success"=>.F., "error"=>"E_LOCK" }

ENDIF

ENDFUNC

FUNCTION SafeRlock()

IF DBRLOCK()

  RETURN { "success"=>.T. }

ELSEIF NETERR()

  RETURN { "success"=>.F., "error"=>"E_NET" }

ELSE

  RETURN { "success"=>.F., "error"=>"E_RLOCK" }

ENDIF

ENDFUNC

FUNCTION SafeUnlock( cFile )

DBUNLOCK()

UNLOCK()

hLocks[ cFile ] := .F.

RETURN { "success"=>.T. }

ENDFUNC

Hat jemand von euch schon Best Practices, wie man so etwas noch robuster gestalten kann (z. B. bei Workarea-Wechsel oder wenn ein USE schiefgeht)?

Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: FLOCK() und RLOCK()
Posted: Tue Aug 26, 2025 12:30 AM
wie DBF-Locking überhaupt funktioniert.

1. File-Lock (FLOCK)

Ein FLOCK() setzt einen Datei-weiten Sperrbereich über den Lock-Mechanismus des Betriebssystems.

Je nach RDD / OS wird dabei in der Regel das ganze File oder ein definierter Bereich (oft Byte 0) gesperrt.

Das Betriebssystem (DOS/Windows: „byte-range locking“, UNIX/NFS: fcntl()/flock()) hält diese Information prozessbezogen.

Gespeichert wird also nur im OS-Kernel, nicht in der DBF selbst.

2. Record-Lock (RLOCK / DBRLOCK)

DBF-Engines (Clipper, Harbour, xHarbour, Xbase++ …) implementieren Record-Locks ebenfalls mit Byte-Range-Locks im Betriebssystem.

Konvention (dBase/Clipper-Standard):

Für Record n wird im DBF-File der Bytebereich n bis n+1 oder eine feste Offset-Formel gelockt.

Beispiel Clipper/DBFNTX: lock at recno * 1, size 1.

ADS/CDX oder andere RDDs nutzen evtl. andere Bereiche, aber immer mit OS-Locks.

Es wird kein zusätzliches Feld in der DBF gesetzt!

Ob ein Datensatz gesperrt ist, weißt du nur durch den Kernel-Lock, nicht durch ein Flag im Record.

3. Wo wird’s gespeichert?

Im Betriebssystem:

Windows: Locktabellen im Kernel (per Filehandle, Prozess, Offset/Length).

UNIX: fcntl(F_SETLK) Strukturen im Kernel.

Jeder Prozess mit demselben Filehandle sieht beim Lock-Versuch: Erfolg oder Fehler.

Die DBF-Datei enthält selbst keinerlei Information über Locks.

4. Konsequenzen

Wenn ein Prozess abstürzt → OS gibt die Locks frei, weil die Filehandles geschlossen werden.

Wenn du dieselbe DBF in zwei Workareas im selben Prozess offen hast → OS sieht nur einen Prozess, die Locks gelten für dich selbst immer als „ok“.

Tools wie IsRecLocked() / DbInfo(DBI_ISFLOCK) fragen im RDD zurück: „halte ich (dieser Prozess) aktuell einen Lock?“ – sie können fremde Locks meist nicht erkennen, nur eigene Versuche schlagen dann fehl.

✅ Kurzantwort:

Gespeichert wird nur im Betriebssystem (Kernel Lock Table), nicht in der DBF.

RLOCK() ist ein Byte-Range-Lock auf die DBF-Datei, typischerweise 1 Byte pro Recno.

Die DBF enthält keine Flag-Spalte für „locked“ – alles passiert über das OS-Locking.
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
Re: FLOCK() und RLOCK()
Posted: Tue Aug 26, 2025 12:31 AM
CHATGPT
Betriebssystem weiß immer, welcher Prozess (genauer: welches Handle dieses Prozesses) einen Lock gesetzt hat.

Wie das OS es hält

Windows (Win32 API / LockFileEx):
Jeder LockFile()/LockFileEx() ruft den Kernel an, der in einer internen Locktabelle pro Filehandle speichert:

Prozess-ID (PID)

Filehandle (weil ein Prozess mehrere Handles auf dieselbe Datei haben kann)

Offset + Länge (welcher Bereich ist gesperrt)

Modus (Shared/Exclusive)

Unix/Linux (fcntl()/flock()):
Ähnlich: der Kernel merkt sich pro Open File Description (d. h. „fd“ in Kombination mit Inode/Dateiobjekt) die Sperrbereiche.

Jeder Prozess hat FDs → die Locktabelle hängt am Dateiknoten.

Bei close() oder Prozessende entfernt der Kernel automatisch die Sperren.

Wichtige Details für DBF-Welt

RLOCK() = „1 Byte locken für Recno N“.
→ Im Kernel ist gespeichert: „PID 12345, Handle #7, File Inode X, Range [1234,1235) ist gelockt“.

FLOCK() = entweder „ganze Datei“ oder z. B. „Byte 0“ exklusiv sperren.

Warum du das im DBF selbst nicht siehst: Die Lockinformationen leben nur im Kernel, nicht in der DBF-Datei.

Darum:

Wenn der Prozess abstürzt → Kernel räumt alle Locks dieses Prozesses auf.

Wenn du denselben Prozess mit zwei Workareas hast → beide Workareas teilen sich dieselbe PID → Kernel erlaubt doppelt „erfolgreich“, weil er sieht: Lock gehört ohnehin dir.

Konsequenz für dich

Ja: Der Kernel speichert genau, welcher Prozess (PID) und welches Handle eine Sperre hält.

Nein: Du kannst das aus deinem Harbour-Programm normalerweise nicht direkt abfragen (außer über spezielle APIs oder Tools wie lsof, handle.exe, Windows API GetFileInformationByHandleEx).

Das RDD selbst arbeitet nach dem Motto: versuch zu locken → klappt = frei, klappt nicht = jemand anders hat’s.

Continue the discussion