<> <> <> DIRECTORY Ascii USING [Upper], Basics USING [BITOR, BITSHIFT, BITXOR], FSLock USING [ActiveFile, ActiveFileObject], FSBackdoor USING [Version], Rope USING [Concat, Equal, InlineFetch, Length, ROPE]; FSLockTableImpl: CEDAR MONITOR IMPORTS Ascii, Basics, Rope EXPORTS FSLock = BEGIN <> LookupLock: PUBLIC ENTRY PROC [prefix, nameBody: Rope.ROPE, version: FSBackdoor.Version] RETURNS [a: FSLock.ActiveFile] = BEGIN hash: CARDINAL; IF Rope.InlineFetch[nameBody, 0] # '[ AND prefix # NIL THEN nameBody _ Rope.Concat[prefix, nameBody]; hash _ Hash[nameBody, version]; lookups _ lookups + 1; FOR a _ lockTbl[hash], a.next UNTIL a = NIL DO IF version = a.version AND Rope.Equal[nameBody, a.nameBody, FALSE] THEN RETURN; ENDLOOP; newActiveFiles _ newActiveFiles + 1; a _ NEW [FSLock.ActiveFileObject]; a.nameBody _ nameBody; a.version _ version; a.h _ NIL; a.fileLock _ none; a.recordLock _ FALSE; a.fileLockCount _ 0; a.attachedTo _ NIL; a.next _ lockTbl[hash]; lockTbl[hash] _ a; END; RemoveLock: PUBLIC ENTRY PROC [a: FSLock.ActiveFile] = BEGIN hash: CARDINAL = Hash[a.nameBody, a.version]; aPrev: FSLock.ActiveFile _ lockTbl[hash]; removals _ removals + 1; IF aPrev = a THEN lockTbl[hash] _ a.next ELSE DO IF aPrev.next = a THEN {aPrev.next _ a.next; EXIT}; aPrev _ aPrev.next; ENDLOOP; a.nameBody _ NIL; END; <> lookups: INT _ 0; newActiveFiles: INT _ 0; removals: INT _ 0; <> buckets: CARDINAL = 509; LockTable: TYPE = ARRAY [0..buckets) OF FSLock.ActiveFile; lockTbl: REF LockTable _ NEW [LockTable _ ALL[NIL]]; Hash: PROC [name: Rope.ROPE, v: FSBackdoor.Version] RETURNS [hash: CARDINAL] = TRUSTED BEGIN OPEN Basics; len: CARDINAL = Rope.Length[name]; hash _ len + v; FOR i: CARDINAL _ 0, i+ 2 WHILE i < len DO hash _ BITOR[BITSHIFT[hash, 1], BITSHIFT[hash, -15]]; hash _ BITXOR[BITSHIFT[CHAR[Ascii.Upper[Rope.InlineFetch[name, i]]].ORD, 8], hash]; IF i+1 < len THEN hash _ BITXOR[CHAR[Ascii.Upper[Rope.InlineFetch[name, i+1]]].ORD, hash]; ENDLOOP; hash _ hash MOD buckets; END; <> Stats: ENTRY PROC RETURNS [items, longestChain: INT, chains: ARRAY [0..10] OF CARDINAL] = BEGIN items _ 0; longestChain _ 0; chains _ ALL[0]; FOR i: CARDINAL IN [0 .. buckets) DO chainLength: INT _ 0; cIndex: CARDINAL; FOR a: FSLock.ActiveFile _ lockTbl[i], a.next UNTIL a = NIL DO chainLength _ chainLength + 1; ENDLOOP; items _ items + chainLength; IF chainLength > longestChain THEN longestChain _ chainLength; cIndex _ MIN [chainLength, 10]; chains[cIndex] _ chains[cIndex] + 1; ENDLOOP; END; END.