Put:
PUBLIC
PROC [ from: YggLog.Block, optr: Camelot.optrT, force:
BOOL, writeID:
BOOL]
RETURNS [thisRecord, followingRecord: RecordID, thisWordNumber: YggEnvironment.WordNumber] =
TRUSTED {
Compute the total length of the block to be written, and touch all pages in it.
totalLen: INT ← 0; -- in 32 bit words
FOR b: YggLog.BlockPtr ← @from, b.rest
UNTIL b =
NIL
DO
len: CARD = b.length;
IF len > 0
THEN {
IF b.base #
NIL
THEN {
offset: CARD ← 0;
UNTIL offset >= len*WordsINWORDS
DO
touch: CARDINAL ← LOOPHOLE[b.base + offset*SIZE[INT32], LONG POINTER TO CARDINAL]^;
IF offset = len - 1 THEN EXIT;
offset ← offset + VM.wordsPerPage/WORDS[CARD32];
IF offset >= len THEN offset ← len - 1;
ENDLOOP;
};
totalLen ← totalLen + len;
};
ENDLOOP;
Total record length must be in correct range.
IF totalLen
NOT
IN [YggLogBasic.minBlockLen .. YggLogBasic.maxBlockLen]
THEN
ERROR CallerProgrammingError;
Append to log, then force to disk if necessary.
Note: tail monitor is not held during force.
[thisRecord, followingRecord, thisWordNumber] ← PutEntry[totalLen, from, force, writeID];
IF force THEN YggLogBasicInternal.ForceTo[followingRecord: followingRecord];
};