LogDBImpl.mesa
Last Edited by: Swinehart, March 24, 1985 1:31:52 pm PST
Reads and write white pages data base records.
DIRECTORY
Atom,
Basics,
BTree,
BTreeSimple,
Commander,
CommandToolExtras,
FS,
IO,
Log,
NamesExtras,
PrincOps,
ProcessProps,
RefTab,
RefText,
Rope,
LogDB,
UserProfile;
LogDBImpl: PROGRAM
IMPORTS Atom, Basics, BTree, BTreeSimple, Commander, CommandToolExtras, FS, IO, Log, NamesExtras, RefTab, ProcessProps, RefText, Rope, UserProfile
EXPORTS LogDB SHARES Rope
= BEGIN
OPEN IO;
ROPE: TYPE = Rope.ROPE;
Attrs: TYPE = LogDB.Attrs;
WPListing: TYPE = LogDB.WPListing;
Representation primitives
Top-level State
WPState: TYPE = LogDB.WPState;
WPStateRecord: TYPE = LogDB.WPStateRecord;
Key Value:
WPValue: TYPE = LONG POINTER TO RECORD [ entryByteAddress: INT ];
Used in enumeration routines to determine actual matches
CompareRopes: PROC[s1: ROPE, s2: ROPE, substringEqual: BOOL]
RETURNS[res: BTreeSimple.Comparison] = {
ss1: INT=Rope.Size[s1];
r2: ROPEIF substringEqual THEN Rope.Substr[s2, 0, ss1] ELSE s2;
RETURN [Rope.Compare[s1, r2, FALSE]];
};
Tables of mappings between small integers (wpAttrs) or external strings (wpExtInt) and attribute names
wpAttrs: RefTab.Ref;
logDB: WPState;
LogDB Procedures
Initialize
InitWhitePagesDatabase: PUBLIC SAFE PROC[
fileName: ROPE, logFileName: ROPE, extIntMapName: ROPE, accessOptions: FS.AccessOptions ← $read,
howToComplain: Log.WhereToReport←$System]
RETURNS[wpState: WPState←NIL] = TRUSTED {
buffer: REF TEXT = RefText.ObtainScratch[100];
s: IO.STREAM;
logDB ← wpState ← NEW[WPStateRecord];
wpState.accessOptions ← accessOptions;
IF fileName=NIL THEN
fileName ← UserProfile.Token[key: "ThrushWPTreeName", default: "///Strowger/WPTree"];
wpState.treeRootName ← FS.ExpandName[fileName].fullFName;
wpState.logFileName ← logFileName;
IF extIntMapName=NIL THEN extIntMapName ←
UserProfile.Token[key:"ThrushWPMappings", default: "/Indigo/Voice/BTree/IntExt.map"];
IF wpAttrs=NIL THEN {
wpAttrs ← RefTab.Create[];
FOR attr: Attrs IN Attrs DO
IF keysForAttributes[attr] # $unassigned THEN
[]←RefTab.Store[wpAttrs, keysForAttributes[attr], NEW[Attrs𡤊ttr]];
ENDLOOP;
};
s ← FS.StreamOpen[extIntMapName];
wpState.wpExtInt ← RefTab.Create[];
WHILE ~s.EndOf[] DO
ENABLE IO.EndOfStream=>EXIT;
int: ATOM ← Atom.MakeAtomFromRefText[s.GetCedarToken[buffer: buffer].token];
ext: ATOM;
[]←s.GetChar[];
ext ← Atom.MakeAtomFromRefText[s.GetLine[buffer]];
[]←wpState.wpExtInt.Store[ext, int]; -- external version is the key.
ENDLOOP;
s.Close[];
RefText.ReleaseScratch[buffer];
[]←OpenWhitePagesDatabase[wpState, howToComplain];
};
Open or reopen
OpenWhitePagesDatabase: SAFE PROC[
wpState: WPState, howToComplain: Log.WhereToReport←$System]
RETURNS [ok: BOOLFALSE] = TRUSTED {
ENABLE BTree.Error => {
Log.Problem["Trouble opening BTree", howToComplain]; CONTINUE };
treeName: ROPE←wpState.treeRootName.Concat[".Tree"];
feepTreeName: ROPE←wpState.treeRootName.Concat[".FTree"];
logFileName: ROPE ← wpState.logFileName;
treeFile, feepFile: FS.OpenFile;
logStream: IO.STREAM;
init: BOOL;
IF wpState=NIL THEN RETURN[FALSE];
IF wpState.wpOpen THEN RETURN;
wpState.wpTree ← BTreeSimple.New[];
wpState.wpFeepTree ← BTreeSimple.New[];
{ ENABLE FS.Error => IF error.group = user THEN {
Log.Problem[error.explanation, howToComplain]; treeFile←FS.nullOpenFile; CONTINUE; };
sbp: FS.StreamBufferParms = [FS.defaultStreamBufferParms.vmPagesPerBuffer, 4];
SELECT wpState.accessOptions FROM
$read => {
treeFile←FS.Open[name: treeName];
feepFile←FS.Open[name: feepTreeName];
logStream ← FS.StreamOpen[fileName: logFileName, streamBufferParms: sbp];
};
$create => {
treeFile←FS.Create[name: treeName, keep: 2, setKeep: TRUE, pages: 100];
feepFile←FS.Create[name: feepTreeName, keep: 2, setKeep: TRUE, pages: 100];
logStream ←
FS.StreamOpen[fileName: logFileName, accessOptions: $write, streamBufferParms: sbp];
};
$write => {
treeFile←FS.OpenOrCreate[name: treeName, keep: 2, pages: 100];
feepFile←FS.OpenOrCreate[name: feepTreeName, keep: 2, pages: 100];
logStream ←
FS.StreamOpen[fileName: logFileName, accessOptions: $write, streamBufferParms: sbp];
};
ENDCASE => Log.Problem["Don't request $append option for BTree", howToComplain];
};
IF treeFile=NIL OR logStream = NIL OR feepFile=NIL THEN RETURN[FALSE];
wpState.wpFile ← treeFile;
wpState.wpFeepFile ← feepFile;
wpState.logStream ← logStream;
init ← wpState.accessOptions = $create OR logStream.GetLength = 0;
BTreeSimple.Open[tree: wpState.wpTree, file: wpState.wpFile, initialize: init];
BTreeSimple.Open[tree: wpState.wpFeepTree, file: wpState.wpFeepFile, initialize: init];
IF wpState.accessOptions = $create THEN wpState.accessOptions ← $write;
ok ← wpState.wpOpen ← TRUE;
};
Close, permanently, or just to get everything up to date
CloseWhitePagesDatabase: PUBLIC SAFE PROC[wpState: WPState,
howToComplain: Log.WhereToReport←$System] RETURNS [ok: BOOLTRUE] = TRUSTED {
IF wpState=NIL OR ~wpState.wpOpen THEN RETURN;
BTreeSimple.SetState[wpState.wpTree, closed!BTree.Error => { ok←FALSE; CONTINUE}];
BTreeSimple.SetState[wpState.wpTree, closed!BTree.Error => { ok←FALSE; CONTINUE}];
wpState.logStream.Close[!FS.Error => IF error.group>=lock THEN CONTINUE];
wpState.wpFile.Close[!FS.Error => IF error.group>=lock THEN CONTINUE];
wpState.wpFeepFile.Close[!FS.Error => IF error.group>=lock THEN CONTINUE];
wpState.wpOpen ← FALSE;
};
Hack because BTrees don't go through FS, so lengths aren't right and copy doesn't work.
SetProperLength: SAFE PROC[name: ROPE] = CHECKED {
pages: INT;
file: FS.OpenFile ← FS.Open[name, $write];
pages ← FS.GetInfo[file].pages;
FS.SetByteCountAndCreatedTime[file, FS.BytesForPages[pages]];
FS.Close[file];
};
Given name and attribute, get value
GetEntry: PUBLIC SAFE PROC[
wpState: WPState, name: ROPENIL, key: ATOM←$officeNumber, feep: BOOLFALSE,
listing: WPListing ← NIL]
RETURNS [fullRName: ROPENIL, entry: ROPENIL, newListing: WPListing←NIL] = TRUSTED {
IF listing = NIL THEN listing ← Lookup[wpState, name, feep];
IF listing = NIL THEN RETURN;
newListing ← listing;
fullRName ← NARROW[listing.Fetch[$rname].val];
IF key#NIL THEN entry ← NARROW[listing.Fetch[key].val];
};
Use specified B-Tree to find and read named entry
Lookup: PUBLIC SAFE PROC[
wpState: WPState, name: ROPE, feep: BOOLFALSE ]
RETURNS [ listing: WPListing←NIL ] = TRUSTED {
name must be in form rr.xxxxxxx
Returns first listing for which name is a substring, case unimportant, of the listing
buffer: REF TEXT ← RefText.ObtainScratch[50];
FindOne: UNSAFE PROC[key: BTreeSimple.EntryKey, value: BTreeSimple.EntryValue]
RETURNS [continue: BOOLEANFALSE] = {
wpValue: WPValue = LOOPHOLE[@value[0]];
byteAddress: INT;
SELECT CompareRopes[name, BTreeSimple.KeyFromEntry[key], TRUE] FROM
greater => RETURN[TRUE];
equal => NULL;
ENDCASE => RETURN[FALSE];
IF feep AND listing#NIL THEN { listing ← NIL; RETURN; };
byteAddress ← wpValue.entryByteAddress;
listing ← ReadEntries[wpState, byteAddress, buffer];
RETURN[feep];
};
IF wpState.wpOpen OR OpenWhitePagesDatabase[wpState] THEN
[]𡤋TreeSimple.EnumerateEntries[
tree: IF feep THEN wpState.wpFeepTree ELSE wpState.wpTree,
key: name, relation: less, Proc: FindOne
];
RefText.ReleaseScratch[buffer];
};
Given address in log file, read entries into a listing structure
ReadEntries: SAFE PROC[
wpState: WPState, byteAddress: INT, buffer: REF TEXT ]
RETURNS [ listing: WPListing←NIL ] = TRUSTED {
entry: IO.STREAM ← wpState.logStream;
recordKey: ATOM;
recordValue: ROPE;
IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN[NIL];
IF byteAddress<0 OR entry.GetLength[]<=byteAddress THEN RETURN[NIL];
entry.SetIndex[byteAddress];
listing ← NewListing[];
DO
code: CHAR;
IF entry.EndOf[] THEN EXIT;
code ← entry.GetChar[];
SELECT code FROM
'\000, '\n => EXIT;
>='\200 => recordKey ← keysForAttributes[LOOPHOLE[-LOOPHOLE[code,INTEGER]]];
ENDCASE => {
ENABLE IO.EndOfStream => CONTINUE;
DefProc: IO.BreakProc = TRUSTED {
RETURN[IF (code𡤌har) = ': THEN break ELSE other]; };
keyRope: REF TEXT;
entry.Backup[code];
keyRope ← entry.GetToken[DefProc, buffer].token;
IF keyRope#NIL AND code = ': THEN {
[] ← entry.GetChar[]; [] ← entry.GetChar[];
recordKey ← Atom.MakeAtomFromRefText[keyRope];
};
};
IF recordKey=NIL THEN EXIT;
recordValue ← entry.GetLineRope[!IO.EndOfStream => {EXIT}];
List[listing, recordKey, recordValue];
ENDLOOP;
};
Given listing and log address representing it, enter into both B-Trees
Enter: SAFE PROC[wpState: WPState, listing: WPListing, byteAddress: INT] = TRUSTED {
SetVal: PROC[value: BTreeSimple.EntryValue] = {
LOOPHOLE[value, LONG POINTER TO CARDINAL]^ ← 2; -- Compensate BTree bug!
LOOPHOLE[@value[0], LONG POINTER TO INT]^ ← byteAddress;
};
name, feepName: ROPE;
IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN;
name ← NARROW[listing.Fetch[$rname].val];
feepName ← NamesExtras.FeepName[name];
BTreeSimple.UpdateEntry[tree: wpState.wpTree, key: name, valueLength: 2, Proc: SetVal];
BTreeSimple.UpdateEntry[tree: wpState.wpFeepTree, key: feepName,
valueLength: 2, Proc: SetVal];
};
Given stream and listing structure, write a log or typescript listing.
WriteEntries: SAFE PROC[stream: IO.STREAM, listing: WPListing] = TRUSTED {
EPA: RefTab.EachPairAction = TRUSTED {
stream.PutF["%g: %g\n", atom[NARROW[key]], rope[NARROW[val]]];
RETURN[FALSE];
};
[]←RefTab.Pairs[listing, EPA];
stream.PutChar['\n];
};
Given a listing, extend the log and enter the result in the B-Trees
LogAndEnter: PUBLIC SAFE PROC[wpState: WPState, listing: WPListing] = TRUSTED {
entry: IO.STREAM;
byteAddress: INT;
IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN;
entry ← wpState.logStream;
byteAddress ← entry.GetLength[];
entry.SetIndex[byteAddress];
WriteEntries[entry, listing];
entry.Flush[];
Enter[wpState, listing, byteAddress];
};
Print listing on primary output; note on error stream if primary is a file
PrintEntries: PUBLIC SAFE PROC[listing: WPListing] = TRUSTED {
h: Commander.Handle = GetCommanderHandle[];
WriteEntries[h.out, listing];
IF h.out#h.err THEN Note[listing];
};
Note name of listing on error stream
Note: SAFE PROC[listing: WPListing] = TRUSTED {
h: Commander.Handle = GetCommanderHandle[];
name: ROPE = NARROW[listing.Fetch[$rname].val];
h.out.Put[rope[name], rope["\n"]];
};
GetCommanderHandle: PROC RETURNS[handle: Commander.Handle] = {
p: Atom.PropList = ProcessProps.GetPropList[];
IF p=NIL THEN RETURN[NIL];
RETURN[NARROW[Commander.GetProperty[$CommanderHandle, p]]];
};
Subsidiary procedures
WhitePagesFill: SAFE PROC[cmd: Commander.Handle, accessOptions: FS.AccessOptions←$write] = TRUSTED {
buffer: REF TEXT;
listing: WPListing←NIL;
wpState: WPState;
numEntries: CARDINAL ← 0;
treeRoot, intExt: ROPE;
entry: IO.STREAM;
byteAddress: INT;
sourceFile: ROPE ← CommandToolExtras.NextArgument[cmd];
IF sourceFile=NIL THEN { Log.Problem["Source file not specified", $System]; RETURN; };
treeRoot ← CommandToolExtras.NextArgument[cmd];
intExt ← CommandToolExtras.NextArgument[cmd];
wpState ← InitWhitePagesDatabase[ treeRoot, sourceFile, intExt, accessOptions];
IF wpState=NIL THEN { Log.Problem["Problem opening B-Trees", $System]; RETURN; };
entry ← wpState.logStream;
entry.SetIndex[byteAddress ← 0];
buffer ← RefText.ObtainScratch[100];
FOR numEntries: NAT IN [0..LAST[NAT]] DO
ENABLE IO.EndOfStream=>EXIT;
entry ← wpState.logStream;
listing ← ReadEntries[wpState, byteAddress, buffer];
IF listing = NIL THEN EXIT;
Note[listing];
Enter[wpState, listing, byteAddress];
byteAddress ← entry.GetIndex[];
ENDLOOP;
RefText.ReleaseScratch[buffer];
(GetCommanderHandle[]).err.PutRope["-- Updates done.\n"];
[]𡤌loseWhitePagesDatabase[wpState];
SetProperLength[wpState.treeRootName.Concat[".Tree"]];
SetProperLength[wpState.treeRootName.Concat[".FTree"]];
};
NewListing: PUBLIC SAFE PROC RETURNS[WPListing] = TRUSTED {RETURN[RefTab.Create[]];};
List: PUBLIC SAFE PROC[listing: WPListing, key: ATOM, value: ROPE] = TRUSTED {
[]←listing.Store[key, value];
};
FillCmdInit: Commander.CommandProc = TRUSTED {
WhitePagesFill[cmd, $create];
};
FillCmd: Commander.CommandProc = TRUSTED {
WhitePagesFill[cmd, $write];
};
keysForAttributes: ARRAY LogDB.Attrs OF ATOM = [
$unassigned, $name, $rName, $officeNumber, $officeDDDNumber, $outsideNumber, $officeAddress, $officeLocation, $organization, $homeAddress, $frequency, $mailSystem, $primaryKey, $unassigned, $unassigned, $unassigned
];
Commander.Register["WPFill", FillCmdInit, "WPFill <textEntriesFile> <treeName <intExtMapName (opt)> (opt)> creates new set of tree files from entries in textEntriesFile"];
Commander.Register["WPRefill", FillCmd, "WPRefill <textEntriesFile> <treeName <intExtMapName (opt)> (opt)> adds to set of tree files from entries in textEntriesFile"];
END.