xref: /plan9/sys/src/cmd/fossil/invariants (revision 00580da515719bdf55c166b53ba7eac22c2e4dd7)
15e96a66cSDavid du Colombier.EQ
25e96a66cSDavid du Colombierdelim $#
35e96a66cSDavid du Colombier.EN
45e96a66cSDavid du Colombier.NH 3
55e96a66cSDavid du ColombierInvariants
6*00580da5SDavid du Colombier.LP
75e96a66cSDavid du ColombierReclamation is tricky enough to warrant explicit statement
85e96a66cSDavid du Colombierof the invariants that are needed and the reasons they are true.
95e96a66cSDavid du ColombierThis section will use the notation
105e96a66cSDavid du Colombier$b.e#
115e96a66cSDavid du Colombierand
125e96a66cSDavid du Colombier$b.e sub 1#
135e96a66cSDavid du Colombierto denote the allocation and
145e96a66cSDavid du Colombierclosing epochs of block
155e96a66cSDavid du Colombier$b#.
165e96a66cSDavid du ColombierThe invariants are:
175e96a66cSDavid du Colombier.IP (i)
185e96a66cSDavid du ColombierIf $b# points at $bb#, then $bb.e <= b.e < bb.e sub 1#.
195e96a66cSDavid du Colombier.IP (ii)
205e96a66cSDavid du ColombierIf $b# points at $bb#, then no other block $b'# with $b'.e = b.e# points at $bb#.
215e96a66cSDavid du Colombier.IP (iii)
225e96a66cSDavid du ColombierIf $b# is not marked
235e96a66cSDavid du Colombier.CW BsCopied
245e96a66cSDavid du Colombierand points at $bb# such that $b.e = bb.e#, then no other block $b'# points at $bb#.
255e96a66cSDavid du Colombier.IP (iv)
265e96a66cSDavid du ColombierIf $b# is in the active file system and points at $bb# then no other block $b'# in the
275e96a66cSDavid du Colombieractive file system points at $bb#.
285e96a66cSDavid du Colombier.IP (v)
295e96a66cSDavid du ColombierIf $b'# is a (possibly indirect) copy of $b#, then only one of $b# and $b'# is in the active file system.
305e96a66cSDavid du Colombier.LP
315e96a66cSDavid du ColombierInvariant (i) lets us reclaim blocks using the file system low epoch.
325e96a66cSDavid du ColombierInvariant (iii) lets us reclaim some blocks immediately once they are unlinked.
335e96a66cSDavid du ColombierInvariants (ii), (iv), and (v) are helpful in proving (i) and (iii); collectively they
345e96a66cSDavid du Colombiersay that taking snapshots doesn't break the active file system.
355e96a66cSDavid du Colombier.PP
365e96a66cSDavid du ColombierFreshly allocated blocks start filled with nil pointers,
375e96a66cSDavid du Colombierand thus satisfy all the invariants.  We need to check that
385e96a66cSDavid du Colombiercopying a block, zeroing a pointer, and setting a pointer
395e96a66cSDavid du Colombierpreserve the invariants.
405e96a66cSDavid du Colombier.LP
415e96a66cSDavid du Colombier$"BlockCopy" (b)#
425e96a66cSDavid du Colombierallocates a new block
435e96a66cSDavid du Colombier$b'# and copies the active and open block $b# into $b'#.
445e96a66cSDavid du Colombier.IP (i)
455e96a66cSDavid du ColombierSince $b# is open, all the blocks $bb# it points to are also
465e96a66cSDavid du Colombieractive, and thus they have $bb.e sub 1# set to positive infinity
475e96a66cSDavid du Colombier(well,
485e96a66cSDavid du Colombier.CW ~0 ).
495e96a66cSDavid du ColombierThus (i) is satisfied.
505e96a66cSDavid du Colombier.IP (ii)
515e96a66cSDavid du ColombierSince $b'.e# will be set to the current epoch, and $b.e# is less
525e96a66cSDavid du Colombierthan the current epoch (it's copy-on-write), $b.e < b'.e# so (ii)
535e96a66cSDavid du Colombieris vacuously satisfied.
545e96a66cSDavid du Colombier.IP (iii)
555e96a66cSDavid du ColombierSince $b.e < b'.e#, all the pointers in $b# are to blocks with epochs less than $b'.e#.
565e96a66cSDavid du ColombierThus (iii) is vacuously satisfied for both $b'#.
575e96a66cSDavid du ColombierSince $"blockCopy"# sets the
585e96a66cSDavid du Colombier.CW BsCopied
595e96a66cSDavid du Colombierflag, (iii) is vacuously satisfied for $b#.
605e96a66cSDavid du Colombier.IP (iv),(v)
615e96a66cSDavid du ColombierSince no pointers to $b# or $b'# were modified,
625e96a66cSDavid du Colombier(iv) and (v) are unchanged.
635e96a66cSDavid du Colombier.LP
645e96a66cSDavid du Colombier$"BlockRemoveLink" (b -> bb)# removes from block $b# the pointer to $bb#
655e96a66cSDavid du Colombier.IP
665e96a66cSDavid du ColombierZeroing a pointer only restricts the preconditions on the
675e96a66cSDavid du Colombierinvariants, so it's always okay.
685e96a66cSDavid du ColombierBy (iii), if $b# is not
695e96a66cSDavid du Colombier.CW BsCopied
705e96a66cSDavid du Colombierand $b.e = bb.e#, then no other $b'# anywhere
715e96a66cSDavid du Colombierpoints at $bb#, so $bb# can be freed.
725e96a66cSDavid du Colombier.LP
735e96a66cSDavid du Colombier$"BlockSetLink" (b->bb sub 0 , bb sub 1)# changes the pointer in block $b# from $bb sub 0# to $bb sub 1#.
745e96a66cSDavid du ColombierWe derive sufficient conditions on $bb sub 1#, and then
755e96a66cSDavid du Colombierexamine the possible values of $bb sub 0# and $bb sub 1#.
765e96a66cSDavid du Colombier.IP (i)
775e96a66cSDavid du ColombierSince we're changing $b#, $b.e# is the current epoch.
785e96a66cSDavid du ColombierIf $bb sub 1# is open, then (i) is satisfied.
795e96a66cSDavid du Colombier.IP (ii)
805e96a66cSDavid du ColombierIf either $b.e != bb sub 1 .e# or $bb sub 1# is an orphan, then (ii) is satisfied.
815e96a66cSDavid du Colombier.IP (iii)
825e96a66cSDavid du ColombierIf either $b.e != bb sub 1 .e# or $b# is marked
835e96a66cSDavid du Colombier.CW BsCopied
845e96a66cSDavid du Colombieror $bb sub 1# is an orphan, then (iii) is satisfied.
855e96a66cSDavid du Colombier.IP (iv)
865e96a66cSDavid du ColombierIf $bb sub 1# is not currently active or $bb sub 1# is an orphan, then (iv) is satisfied.
875e96a66cSDavid du Colombier.IP (v)
885e96a66cSDavid du ColombierIf $bb sub 1# is a copy of $bb sub 0# or $bb sub 1# is empty, then (v) is satisfied.
895e96a66cSDavid du Colombier.LP
905e96a66cSDavid du Colombier$"BlockSetLink" (b -> bb sub 0 , "blockAlloc" ())# allocates a new block and points $b# at it.
915e96a66cSDavid du Colombier.IP
925e96a66cSDavid du ColombierSince $bb sub 1# in this case is newly allocated, it is open, an orphan, and empty, and thus
935e96a66cSDavid du Colombierthe invariants are satisfied.
945e96a66cSDavid du Colombier.LP
955e96a66cSDavid du Colombier$"BlockSetLink" (b -> bb sub 0 , "blockCopy" (bb sub 0 ))# copies $bb sub 0# and points
965e96a66cSDavid du Colombier$b# at the copy.
975e96a66cSDavid du Colombier.IP
985e96a66cSDavid du ColombierSince $bb sub 1# is newly allocated, it is open and an orphan.  Thus (i)-(iv) are satisfied.
995e96a66cSDavid du ColombierSince $bb sub 1# is a copy of $bb sub 0#, (v) is satisfied.
1005e96a66cSDavid du Colombier.LP
1015e96a66cSDavid du Colombier$"BlockSetLink" (b -> "nil" , "oldRoot" )# changes a nil pointer to point
1025e96a66cSDavid du Colombierat a snapshot root.
1035e96a66cSDavid du Colombier.IP (i)
1045e96a66cSDavid du ColombierInvariant (i) is broken, but the
1055e96a66cSDavid du Colombier.CW snap
1065e96a66cSDavid du Colombierfield in the entry will be used to make sure
1075e96a66cSDavid du Colombierwe don't access the snapshot after it has been reclaimed.
1085e96a66cSDavid du Colombier.IP (ii)
1095e96a66cSDavid du ColombierSince the epoch of  $"oldRoot"# is less than the current epoch but $b.e# is equal
1105e96a66cSDavid du Colombierto the current epoch, (ii) is vacuously true.
1115e96a66cSDavid du Colombier.IP (iii)
1125e96a66cSDavid du ColombierXXX
1135e96a66cSDavid du Colombier.IP (iv)
1145e96a66cSDavid du ColombierXXX
1155e96a66cSDavid du Colombier.IP (v)
1165e96a66cSDavid du ColombierXXX
1175e96a66cSDavid du Colombier.PP
1185e96a66cSDavid du ColombierTa da!
1195e96a66cSDavid du Colombierxxx
1205e96a66cSDavid du Colombieryyyy
1215e96a66cSDavid du Colombierzzz
122