1: % Modification of version of 28 July 2004
2: % Started 19 October 2004
3: \documentclass{article}
4: \usepackage[english]{babel}
5: %\usepackage{moreverb}
6:
7: \usepackage{latexsym}
8: \usepackage{amssymb}
9:
10: \newenvironment{tab}{\begin{tabbing}
11: MMMMM\=aaa\=aaa\=aaa\=aaa\=aaa\=aaa\= \kill}{\end{tabbing}}
12:
13: \makeatletter
14: \def\refmystepcounter#1{\stepcounter{#1}\protect\gdef
15: \@currentlabel {\csname p@#1\endcsname \csname
16: the#1\endcsname}}
17: \makeatother
18: \newcounter {tabnr}
19: \newenvironment{tabn}{\begin{tabbing}
20: \refmystepcounter{tabnr}
21: MMMMM\=aaa\=aaa\=aaa\=aaa\=aaa\=aaa\= \kill
22: (\arabic{tabnr})~}{\end{tabbing}}
23:
24: \newcommand{\nrule}{\refmystepcounter{tabnr}
25: \mbreak(\arabic{tabnr})~}
26:
27: \newenvironment{ta}{\begin{tabbing}
28: MM\=aa\=aa\=aa\=aa\=aa\=aa\= \kill}{\end{tabbing}}
29:
30: \def\boks {\mbox{$\Box$}}
31: \def\Nat {\mbox{$\mathbb{N}$}}
32: \def\IB {\mbox{$\mathbb{B}$}}
33: \def\IR {\mbox{$\mathbb{R}$}}
34: \def\IC {\mbox{$\mathbb{C}$}}
35: \def\IP {\mbox{$\mathbb{P}$}}
36: \def\IQ {\mbox{$\mathbb{Q}$}}
37: \def\IZ {\mbox{$\mathbb{Z}$}}
38: \def\Oh{{\cal O}}
39: \def\OPEN {\mbox{$|\![ \: $}}
40: \def\CLOSE {\mbox{$\: ]\!| $}}
41: \def\bar {\mbox{$[ \! ]$}}
42: \def\ang {\mbox{$\,\diamondsuit\,$}}
43: \def\all {\forall\;}
44: \def\ex {\exists\;}
45: \def\sqleq {\sqsubseteq}
46: \def\omit#1{}
47: \def\S #1/{\mbox {\textsl{#1}}}
48: \def\B #1/{\mbox {\textbf{#1}}}
49: \def\R #1/{\mbox {\textrm{#1}}}
50: \def\T #1/{\mbox {\texttt{#1}}}
51: \def\from {\:\leftarrow\:}
52: \def\leadsto {\mbox{$\:o\!\!\to\:$}}
53: \def\Leadsto {\mbox{$\quad o\!\!\to\quad $}}
54: \def\la {\mbox{$\langle$}}
55: \def\ra {\mbox{$\rangle$}}
56: \def\Com {\mbox {$\quad\{ $}}
57: \def\com {\mbox {$ \{ $}}
58: \def\moc {\mbox {$ \}\; $}}
59: \def\Moc {\mbox {$ \}\quad $}}
60: \def\comm {\mbox {$ (*\; $}}
61: \def\Comm {\mbox {\quad $ (*\; $}}
62: \def\mmoc {\mbox {$ \;*) $}}
63: \def\eps {{\mbox{$\varepsilon$}}}
64: \def\phi {{\mbox{$\varphi$}}}
65: \def\implies{\mbox{$\Rightarrow $}}
66: \def\follows{\mbox{$\Leftarrow $}}
67: \def\Implies{\mbox{$\;\Rightarrow\; $}}
68: \def\IMPLIES{\mbox{$\quad\Rightarrow\quad $}}
69: \def\EQ {\mbox{\quad$\equiv$\quad}}
70: \def\eq {\mbox{$\equiv\,$}}
71: \def\LAND {\mbox{\quad$\land$\quad}}
72: \def\Land {\mbox{ $\;\land\;$ }}
73: \def\LOR {\mbox{$\quad\lor\quad$}}
74: \def\Lor {\mbox{$\;\lor\;$}}
75: \def\LEQ {\mbox{$\quad\leq\quad$}}
76: \def\TO {\mbox{$\quad\to\quad$}}
77: \def\true {\S true/}
78: \def\false {\S false/}
79: \def\IS {\mbox{$\quad =\quad $}}
80: \def\remark {\medbreak\noindent{\sl Remark.\/} }
81: \def\remarks{\medbreak\noindent{\sl Remarks.\/} }
82: \def\sbreak {\smallbreak\noindent}
83: \def\mbreak {\medbreak\noindent}
84: \def\bbreak {\bigbreak\noindent}
85: \def\proof {\mbreak{\sl Proof.\/} }
86: \def\example{\mbreak{\sl Example.\/} }
87: \def\MIN {\T MIN /}
88: \def\MAX {\T MAX /}
89: \def\min {\B\ min /}
90: \def\max {\B\ max /}
91: \def\DOTS {\mbox{\ .\ .\ }}
92: \def\half {\mbox{$1\over 2$}}
93: \def\bol {\mbox{$\bullet$}}
94:
95: \newcounter{theoremcnt}[section]
96: \newcommand{\qed}{\hfill$\quad\Box$}
97: \renewcommand{\thetheoremcnt}{\thesection.\arabic{theoremcnt}}
98:
99: \newenvironment{Tm}%
100: {\begin{trivlist}\refstepcounter{theoremcnt}
101: \item[]\bf Theorem~\thetheoremcnt.~\rm}{\end{trivlist}}
102:
103: \pagestyle {myheadings}
104: \markright{\hfill Lock-free Dynamic Hash Tables -- }
105:
106: \begin{document}
107:
108: \begin {center}
109: {\Large\bf Lock-free Dynamic Hash Tables \\
110: with Open Addressing}\\
111: \mbox{}\\
112: Gao, H.$^1$, Groote, J.F.$^2$, Hesselink, W.H.$^1$\\
113: {\small
114: $^1$ Department of Mathematics and Computing Science, University of
115: Groningen,\\
116: P.O. Box 800, 9700 AV Groningen, The Netherlands (Email:
117: \verb!{hui,wim}@cs.rug.nl!)\\
118: $^2$ Department of Mathematics and Computing Science,
119: Eindhoven University of Technology, P.O. Box 513, 5600 MB
120: Eindhoven, The Netherlands and CWI,\\
121: P.O. Box 94079, 1090 GB Amsterdam, The Netherlands
122: (Email: \verb!jfg@win.tue.nl!)}
123: \end{center}
124:
125: \begin{abstract}
126:
127: \noindent
128: We present an efficient lock-free algorithm for parallel
129: accessible hash tables with open addressing, which promises more
130: robust performance and reliability than conventional lock-based
131: implementations. ``Lock-free'' means that it is guaranteed
132: that always at least one process completes its operation within
133: a bounded number of steps. For a single processor architecture
134: our solution is as efficient as sequential hash tables. On a
135: multiprocessor architecture this is also the case when all
136: processors have comparable speeds. The algorithm allows processors
137: that have widely different speeds or come to a halt. It can easily be
138: implemented using C-like languages and requires on average only
139: constant time for insertion, deletion or accessing of elements.
140: The algorithm allows the hash tables to grow and shrink when needed.
141:
142: Lock-free algorithms are hard to
143: design correctly, even when apparently straightforward. Ensuring
144: the correctness of the design at the earliest possible stage is a
145: major challenge in any responsible system development. In view of
146: the complexity of the algorithm, we turned to the interactive
147: theorem prover PVS for mechanical support. We employ standard
148: deductive verification techniques to prove around 200 invariance
149: properties of our algorithm, and describe how this is achieved with
150: the theorem prover PVS.
151: \end{abstract}
152:
153: \mbreak
154: {\it CR Subject Classification (1991):}
155: {\sf D.1 Programming techniques}\\
156: {\it AMS Subject Classification (1991):} {\sf 68Q22 Distributed
157: algorithms, 68P20 Information storage and retrieval}\\
158: {\it Keywords \& Phrases:} {\sf Hash tables, Distributed algorithms,
159: Lock-free, Wait-free}
160:
161: \section{Introduction}
162: We are interested in efficient, reliable, parallel algorithms.
163: The classical synchronization paradigm based on mutual exclusion
164: is not most suited for this, since mutual exclusion often turns
165: out to be a performance bottleneck, and failure of a single process
166: can force all other processes to come to a halt. This is the reason
167: to investigate lock-free or wait-free concurrent objects, see e.g.\
168: \cite{Bar93,Her91,Her93,HeM92,HG99,KS97,LaMa94,Mic02,RaG02,ShS03,
169: SuT04,Valois94}.
170:
171: \subsubsection*{Lock-free and wait-free objects}
172:
173: A \emph{concurrent object} is an abstract data type that
174: permits concurrent operations that appear to be atomic
175: \cite{Her91,Lyn96,Valois94}. The easiest way to implement
176: concurrent objects is by means of mutual exclusion, but
177: this leads to blocking when the process that holds
178: exclusive access to the object is delayed or stops
179: functioning.
180:
181: The object is said to be \emph{lock-free} if any process
182: can be delayed at any point without forcing any other
183: process to block and when, moreover, it is guaranteed that
184: always some process will complete its operation in a
185: finite number of steps, regardless of the execution speeds
186: of the processes \cite{Bar93,Her93,LaMa94,RaG02,Valois94}.
187: The object is said to be \emph{wait-free} when it is
188: guaranteed that any process can complete any operation in
189: a finite number of steps, regardless of the speeds of the
190: other processes \cite {Her91}.
191:
192: We regard ``non-blocking'' as synonymous to ``lock-free''. In several
193: recent papers, e.g. \cite{SuT04}, the term ``non-blocking'' is used
194: for the first conjunct in the above definition of lock-free. Note that
195: this weaker concept does not in itself guarantee progress. Indeed,
196: without real blocking, processes might delay each other arbitrarily
197: without getting closer to completion of their respective operations.
198: The older literature \cite{ARJ97,Bar93,HeM92} seems to suggest that
199: originally ``non-blocking'' was used for the stronger concept, and
200: lock-free for the weaker one. Be this as it may, we use lock-free
201: for the stronger concept.
202:
203: \subsubsection*{Concurrent hash tables}
204:
205: The data type of hash tables is very commonly used to efficiently
206: store huge but sparsely filled tables. Before 2003, as far as we
207: know, no lock-free algorithm for hash tables had been
208: proposed. There were general algorithms for arbitrary wait-free
209: objects \cite{ABD90,BD89,Bar93,Her91,H95,H96}, but these are not
210: very efficient. Furthermore, there are lock-free algorithms for
211: different domains, such as linked lists \cite{Valois94}, queues
212: \cite{Valois92} and memory management \cite{HeM92,HG99}.
213:
214: In this paper we present a lock-free algorithm for hash
215: tables with open addressing that is in several
216: aspects wait-free. The central idea is that every process
217: holds a pointer to a hash table, which is the current one if the
218: process is not delayed. When the current hash table is full, a new
219: hash table is allocated and all active processes join in the
220: activity to transfer the contents of the current table to the new
221: one. The consensus problem of the choice of a new table is solved
222: by means of a test-and-set register. When all processes have left
223: the obsolete table, it is deallocated by the last one leaving. This
224: is done by means of a compare-and-swap register. Measures have been
225: taken to guarantee that actions of delayed processes are never
226: harmful. For this purpose we use counters that can be incremented
227: and decremented atomically.
228:
229: After the initial design, it took us several years to establish the
230: safety properties of the algorithm. We did this by means of the
231: proof assistant PVS \cite{OSR01}. Upon completion of this proof, we
232: learned that a lock-free resizable hash table based on chaining was
233: proposed in \cite{ShS03}. We come back to this below.
234:
235: Our algorithm is lock-free and some of the subtasks are wait-free.
236: We allow fully parallel \S insertion/, \S assignment/, \S deletion/,
237: and \S finding/ of elements. Finding is wait-free, the other three
238: are not. The primary cause is that the process executing it may
239: repeatedly have to execute or join a migration of the hash table.
240: Assignment and deletion are also not wait-free when other processes
241: repeatedly assign to the same address successfully.
242:
243: Migration is called for when the
244: current hash table is almost filled. This occurs when the table has
245: to grow beyond its current upper bound, but also for maintenance
246: after many insertions and deletions. The migration itself is
247: wait-free, but, in principle, it is possible that a slow process is
248: unable to access and use a current hash table since the current hash
249: table is repeatedly replaced by faster processes.
250:
251: Migration requires subtle provisions, which can be best understood
252: by considering the following scenario. Suppose that process $A$ is
253: about to (slowly) insert an element in a hash table $H_1$. Before
254: this happens, however, a fast process $B$ has performed migration
255: by making a new hash table $H_2$, and copying the content from
256: $H_1$ to $H_2$. If (and only if) process $B$ did not copy the
257: insertion of $A$, $A$ must be informed to move to the new hash table,
258: and carry out the insertion there. Suppose a process $C$ comes into
259: play also copying the content from $H_1$ to $H_2$. This must be
260: possible, since otherwise $B$ can stop copying, blocking all
261: operations of other processes on the hash table, and thus violating
262: the lock-free nature of the algorithm. Now the value inserted by
263: $A$ can but need not be copied by both $B$ and/or $C$. This can be
264: made more complex by a process $D$ that attempts to replace $H_2$ by
265: $H_3$. Still, the value inserted by $A$ should show up exactly once
266: in the hash table, and it is clear that processes should carefully
267: keep each other informed about their activities on the tables.
268:
269: \subsubsection*{Performance, comparison, and correctness}
270:
271: For a single processor architecture our solution is of the same order
272: of efficiency as sequential hash tables. Actually, only an extra check
273: is required in the main loop of the main functions, one extra bit
274: needs to be set when writing data in the hashtables and at some places
275: a write operation has been replaced by a compare and swap, which is
276: more expensive. For ordinary operations on the hashtable, this is the
277: only overhead and therefore a linear speed up can be expected on
278: multiprocessor systems. The only place where no linear speed up can be
279: achieved is when copying the hashtable. Especially, when processes
280: have widely different speeds, a logaritmic factor may come into play
281: (see algorithms for the write all problem \cite{Jan00,KS97}). Indeed,
282: initial experiments indicate that our algorithm is as efficient as
283: sequential hash tables. It seems to require on average only constant
284: time for insertion, deletion or accessing of elements.
285:
286: Some differences between our algorithm and the algorithm of
287: \cite{ShS03} are clear. In our algorithm, the hashed values need not
288: be stored in dynamic nodes if the address-value pairs (plus one
289: additional bit) fit into one word.
290: Our hash table can shrink whereas the table of bucket headers in
291: \cite{ShS03} cannot shrink. A disadvantage of our algorithm, due
292: to its open addressing, is that migration is needed as maintenance
293: after many insertions and deletions.
294:
295: An apparent weakness of our algorithm is the worst-case space
296: complexity in the order of $\Oh(P M)$ where $P$ is the number of
297: processes and $M$ is the size of the table. This only occurs when many
298: of the processes fail or fall asleep while using the hash
299: table. Failure while using the hash table can be made less probable by
300: adequate use of procedure ``releaseAccess''. This gives a trade-off
301: between space and time since it introduces the need of a corresponding
302: call of ``getAccess''. When all processes make ordinary progress and
303: the hash table is not too small, the actual memory requirement in
304: $\Oh(M)$.
305:
306: The migration activity requires worst-case $\Oh(M^2)$ time for each
307: participating process. This only occurs when the migrating processes
308: tend to choose the same value to migrate and the number of collisions
309: is $\Oh(M)$ due to a bad hash function.
310: This is costly, but even this is in agreement with
311: wait-freedom. The expected amount of work for migration for all
312: processes together is $\Oh(M)$ when collisions are sparse,
313: as should be the case when migrating to a hash table that is
314: sufficiently large.
315:
316: A true problem of lock-free algorithms is that they are hard to
317: design correctly, which even holds for apparently straightforward
318: algorithms. Whereas human imagination generally suffices to deal
319: with all possibilities of sequential processes or synchronized
320: parallel processes, this appears impossible (at least to us)
321: for lock-free algorithms. The only technique that we see fit
322: for any but the simplest lock-free algorithms is to prove the
323: correctness of the algorithm very precisely, and to verify this
324: using a proof checker or theorem prover.
325:
326: As a correctness notion, we take that the operations behave the same
327: as for `ordinary' hash tables, under some arbitrary linearization
328: \cite{HeW90} of these operations. So, if a \S find/ is carried out
329: strictly after an \S insert/, the inserted element is found. If
330: \S insert/ and \S find/ are carried out at the same time, it may be
331: that \S find/ takes place before \S insertion/, and it is not
332: determined whether an element will be returned.
333:
334: Our algorithm contains 81 atomic statements. The structure of our
335: algorithm and its correctness properties, as well as the complexity
336: of reasoning about them, makes neither automatic nor manual
337: verification feasible. We have therefore chosen the higher-order
338: interactive theorem prover PVS \cite{FCB00,OSR01} for mechanical
339: support. PVS has a convenient specification language and contains
340: a proof checker which allows users to construct proofs
341: interactively, to automatically execute trivial proofs, and to
342: check these proofs mechanically.
343:
344: \subsubsection*{Overview of the paper}
345:
346: Section \ref{interface} contains the description of the hash table
347: interface offered to the users. The algorithm is presented in
348: Section \ref{algorithm}. Section \ref{safety} contains a description
349: of the proof of the safety properties of the algorithm: functional
350: correctness, atomicity, and absence of memory loss. This proof is
351: based on a list of around 200 invariants, presented in Appendix A,
352: while the relationships between the invariants are given by a
353: dependency graph in Appendix B.
354: Progress of the algorithm is proved informally in Section
355: \ref{progress}.
356: Conclusions are drawn in Section \ref{conclusions}.
357:
358: \section{The interface}\label{interface}
359:
360: The aim is to construct a hash table that can be
361: accessed simultaneously by different processes in such
362: a way that no process can passively block another
363: process' access to the table.
364:
365: A hash table is an implementation of (partial) functions between
366: two domains, here called \S Address/ and $\S Value/$. The hash
367: table thus implements a modifiable shared variable
368: $\T X/: \S Address/\to\S Value/$.
369: The domains \S Address/ and \S Value/ both contain special
370: default elements $0\in\S Address/$ and $\B null/\in\S Value/$.
371: An equality $\T X/(a )=\B null/$ means that no value is currently
372: associated with the address $a$.
373: In particular, since we never store a value for the address $0$,
374: we impose the invariant
375: \begin {tab}
376: \> $ \T X/(0)=\B null/$ .
377: \end {tab}
378: We use open addressing to keep all elements within the table.
379: For the implementation of the hash table we require
380: that from every value the address it corresponds to is derivable.
381: We therefore assume that some function
382: $\S ADR/: \S Value/\to\S Address/$ is given with the property that
383: \begin{tab} %ADRjective
384: \S Ax1:/ \>$~~~v=\B null/~\equiv ~ \S ADR/(v)= 0 $
385: \end{tab}
386: Indeed, we need \B null/ as the value corresponding to the undefined
387: addresses and use address 0 as the (only) address associated with
388: the value \B null/. We thus require the hash table to satisfy the
389: invariant
390: \begin {tab}
391: \> $ \T X/(a) \ne \B null/\IMPLIES
392: \S ADR/(\T X/(a))= a$ .
393: \end {tab}
394: Note that the existence of \S ADR/ is not a real restriction since
395: one can choose to store the pair $(a,v)$ instead of $v$. When $a$
396: can be derived from $v$, it is preferable to store $v$, since that
397: saves memory.
398:
399: There are four principle operations: \S find/,
400: \S delete/, \S insert/ and \S assign/.
401: The first one is to \S find/ the
402: value currently associated with a given address. This
403: operation yields $\B null/$ if the address has no associated value.
404: The second operation is to \S delete/ the
405: value currently associated with a given address. It fails
406: if the address was empty, i.e.\ $\T X/(a)=\B null/$.
407: The third operation is to \S insert/ a new value for a given
408: address, provided the address was empty. So, note that
409: at least one out of two consecutive $\S insert/$s for address $a$
410: must fail, except when there is a $\S delete/$ for address $a$ in
411: between them. The operation $\S assign/$ does the same
412: as \S insert/, except that it rewrites the value even if the
413: associated address is not empty. Moreover, \S assign/ never fails.
414:
415: We assume that there is a bounded number of processes that
416: may need to interact with the hash table. Each process is
417: characterized by the sequence of operations
418: \begin{tab}
419: \> $(\; \S getAccess/\;;\;
420: (\S find/+\S delete/+\S insert/+\S assign/)^*\;;\;
421: \S releaseAccess/ )^\omega $
422: \end{tab}
423: A process that needs to access the table, first calls the
424: procedure \S getAccess/ to get the current hash table pointer.
425: It may then invoke the procedures \S find/, \S delete/, \S insert/,
426: and \S assign/ repeatedly, in an arbitrary, serial manner.
427: A process that has access to the table can call \S releaseAccess/
428: to log out. The processes may call these procedures concurrently.
429: The only restriction is that every process can do at most one
430: invocation at a time.
431:
432: The basic correctness conditions for concurrent systems are
433: functional correctness and atomicity, say in the sense of
434: \cite{Lyn96},
435: Chapter 13. Functional correctness is expressed by prescribing how
436: the procedures \S find/, \S insert/, \S delete/, \S assign/ affect
437: the value of the abstract mapping \T X/ in relation to the return
438: value. Atomicity means that the effect on \T X/ and the return value
439: takes place atomically at some time between the invocation of the
440: routine and its response.
441: Each of these procedures has the precondition
442: that the calling process has access to the table. In this
443: specification, we use auxiliary private variables declared
444: locally in the usual way. We give them the suffix $S$ to
445: indicate that the routines below are the specifications of the
446: procedures. We use angular brackets \la\ and \ra\ to indicate
447: atomic execution of the enclosed command.
448: \begin {tab}
449: \> $ \B proc /\S find/_S (a:\S Address/\setminus\{0\}) :
450: \S Value/ = $\\
451: \>\>\B local/ $rS:\S Value/$;\\
452: (fS) \>\>\la~$rS:=\; \T X/(a)\;\ra $;\\
453: \>\B return/ $rS$.
454: \end{tab}
455:
456: \begin {tab}
457: \> $ \B proc /\S delete/_S (a:\S Address/\setminus\{0\}) :
458: \S Bool/ = $\\
459: \>\>\B local/ $\S sucS/:\S Bool/$;\\
460: (dS) \>\>\la~$ \S sucS/:=(\T X/(a)\not=\B null/)$ ; \\
461: \>\>~~$ \B if /\;\S sucS/\; \B\ then /\;
462: \T X/(a):=\B null/\;\B\ end /\ra$ ;\\
463: \>\B return/ $\S sucS/$.
464: \end{tab}
465:
466: \begin{tab}
467: \>\B proc/ $\S insert/_S (v:\S Value/\setminus\{\B null/\}) :
468: \S Bool/ = $\\
469: \>\>\B local/ $\S sucS/:\S Bool/\;;\; a:\S Address/:= \S ADR/(v) $ ;\\
470: (iS) \>\>\la~$ \S sucS/:=(\T X/(a)=\B null/)$ ;\\
471: \>\>~~$ \B if /\;\S sucS/\; \B\ then /\; \T X/(a):=v\;\B\ end /\ra $ ;\\
472: \>\B return/ $\S sucS/$.
473: \end{tab}
474:
475: \begin {tab}
476: \>$\B proc /\S assign/_S(v:\S Value/\setminus\{\B null/\})= $\\
477: \>\>\B local/ $ a:\S Address/:= \S ADR/(v) $ ;\\
478: (aS) \>\>\la~$\T X/(a):=v \; \ra $ ;\\
479: \>\B end/.
480: \end{tab}
481: Note that, in all cases, we require that the body of the
482: procedure is executed atomically at some moment between the
483: beginning and the end of the call, but that this moment need not
484: coincide with the beginning or end of the call. This is the reason
485: that we do not (e.g.) specify \S find/ by the single line
486: $\B return /\T X/(a) $.
487:
488: Due to the parallel nature of our system we cannot use pre and
489: postconditions to specify it. For example, it may happen that
490: $\S insert/(v)$ returns \true\ while $\T X/(\S ADR/(v))\ne v $
491: since another process deletes $\S ADR/(v)$ between the execution
492: of (iS) and the response of \S insert/.
493:
494: In Section \ref{primary}, we provide implementations for the
495: operations \S find/, \S delete/, \S insert/, \S assign/.
496: We prove partial correctness of the implementations by extending them
497: with the auxiliary variables and commands used in the specification.
498: So, we regard \T X/ as a shared auxiliary variable and $rS$
499: and $\S sucS/$ as private auxiliary variables; we augment the
500: implementations of \S find/, \S delete/, \S insert/, \S assign/
501: with the atomic commands (fS), (dS), (iS), (aS), respectively.
502: We prove that each of the four implementations executes
503: its specification command always exactly once and that the
504: resulting value $r$ or $\S suc/$ of the implementation equals the
505: resulting value $rS$ or $\S sucS/$ in the specification. It follows
506: that, by removing the
507: implementation variables from the combined program, we obtain the
508: specification. This removal may eliminate many atomic steps of the
509: implementation. This is known as removal of stutterings in TLA
510: \cite{Lam94} or abstraction from $\tau$ steps in process algebras.
511:
512: \section{The algorithm} \label{algorithm}
513:
514: An implementation consists of $P$ processes along with a set of
515: variables, for $P\geq 1$. Each process, numbered from $1$ up to $P$,
516: is a sequential program comprised of atomic statements. Actions on
517: private variables can be added to an atomic statement, but all
518: actions on shared variables must be separated into atomic accesses.
519: Since auxiliary variables are only used to facilitate the
520: proof of correctness, they can be assumed to be touched instantaneously
521: without violation of the atomicity restriction.
522:
523: \subsection{Hashing}
524:
525: We implement function \T X/ via hashing with open addressing, cf.\
526: \cite{Knuth3,Wir}. We do not use direct chaining, where colliding
527: entries are stored in a secondary list, as is done in \cite {ShS03}.
528: A disadvantage of open addressing with deletion of elements is that
529: the contents of the hash table must regularly be refreshed by copying
530: the non-deleted elements to a new hash table.
531: As we wanted to be able to resize the hash tables
532: anyhow, we consider this less of a burden.
533:
534: In principle, hashing is a way to store address-value pairs
535: in an array (hash table) with a length much smaller than the
536: number of potential addresses. The indices of the array are
537: determined by a hash function. In case the hash function maps
538: two addresses to the same index in the array there
539: must be some method to determine an alternative index.
540: The question how to choose a good hash function and how to
541: find alternative locations in the case of open addressing is
542: treated extensively elsewhere, e.g.\ \cite{Knuth3}.
543:
544: For our purposes it is convenient to combine these two roles in
545: one abstract function \S key/ given by:
546: \begin {tab}
547: \> $ \S key/(a: \S Address/,\;l:\S Nat/,\;n:\S Nat/):\S Nat/$ ,
548: \end {tab}
549: where $l$ is the length of the array (hash table), that satisfies
550: \begin{tab}
551: \S Ax2:/ \>$ 0\leq \S key/(a,l,n) < l$
552: \end{tab}
553: for all $a$, $l$, and $n$. The number $n$ serves to
554: obtain alternative locations in case of collisions:
555: when there is a collision, we re-hash until an empty ``slot''
556: (i.e. \B null/) or the same address in the table is found.
557: The approach with a third argument $n$ is unusual but
558: very general. It is more usual to have a function
559: \S Key/ dependent on $a$ and $l$, and use a second
560: function \S Inc/, which may depend on $a$ and $l$, to use in
561: case of collisions. Then our function \S key/ is
562: obtained recursively by
563: \begin {tab}
564: \>\+ $ \S key/(a,l,0) = \S Key/(a,l)$ and
565: $ \S key/(a,l,n+1) = \S Inc/(a,l,\S key/(a,l,n)) $ .
566: \end {tab}
567: We require that, for any address $a$ and any number $l$,
568: the first $l$ keys are all different, as expressed in
569: \begin {tab}
570: \S Ax3:/ \> $ 0\leq k < m < l \IMPLIES
571: \S key/(a,l,k) \ne \S key/(a,l,m) $ .
572: \end {tab}
573:
574: \subsection{Tagging of values}
575:
576: As is well known \cite{Knuth3}, hashing with open addressing needs
577: a special value $\B del/\in \S Value/$ to replace deleted values.
578:
579: When the current hash table becomes full, the processes need to reach
580: consensus to allocate a new hash table of new size to replace the
581: current one. Then all values except \B null/ and \B del/ must be
582: migrated to the new hash table. A value that is being migrated
583: cannot be simply removed, since the migrating process may stop
584: functioning during the migration. Therefore, a value being copied
585: must be tagged in such a way that it is still recognizable. This is
586: done by the function \S old/. We thus introduce
587: an extended domain of values to be called \S EValue/,
588: which is defined as follows:
589: \begin{tab}
590: \>\S EValue/ = $\{ \B del/\}\cup\S Value/\cup
591: \{\S old/(v)~|~v\in \S Value/\}$
592: \end{tab}
593: We furthermore assume the existence of functions
594: $\S val/: \S EValue/\to\S Value/$ and $\S oldp/: \S EValue/\to\S Bool/$ that satisfy, for all $v\in \S Value/$:
595: \begin{tab}
596: \>$\S val/(v)=v$ \>\>\>\>\>\> $\S oldp/(v)=\false$\\
597: \>$\S val/(\B del/)=\B null/$ \>\>\>\>\>\> $\S oldp/(\B del/)=\false$\\
598: \>$\S val/(\S old/(v))=v$ \>\>\>\>\>\> $\S oldp/(\S old/(v))=\true$
599: \end{tab}
600: Note that the \S old/ tag can easily be implemented by
601: designating one special bit in the representation of \S Value/.
602: In the sequel we write $\B done/$ for $\S old/(\B null/)$.
603: Moreover, we extend the function $\S ADR/$ to domain $\S EValue/$
604: by $\S ADR/(v)=\S ADR/(\S val/(v))$.
605:
606: \subsection {Data structure}
607:
608: A \S Hash table/ is either $\bot$, indicating the absence of a
609: hash table, or it has the following structure:
610: \begin{tab}
611: \>$\T size, bound, occ, dels/ :\S Nat/$;\\
612: \>$\T table/:\B array / 0\DOTS\T size-1 /\B of/ \S\ EValue/$.
613: \end{tab}
614: The field \T size/ indicates the size of the hash table,
615: \T bound/ the maximal number of places that
616: can be occupied before refreshing the table. Both
617: are set when creating the table and remain constant. The
618: variable \T occ/ gives the number of occupied positions in
619: the table, while the variable \T dels/ gives the number of deleted
620: positions. If $h$ is a pointer to a hash table, we write
621: $h.\T size/$, $h.\T occ/$, $h.\T dels/$ and
622: $h.\T bound/$ to access these fields of the hash table. We write
623: $h.\T table/[i]$ to access the $i^{\rm th}$ \S EValue/ in
624: the table.
625:
626: Apart from the \S current/ hash table, which is the main representative
627: of the variable \T X/, we have to deal with \S old/ hash tables, which
628: were in use before the current one, and \S new/ hash tables, which can be
629: created after the current one.
630:
631: We now introduce data structures that are used by the processes
632: to find and operate on the hash table and allow to
633: delete hash tables that are not used anymore. The basic idea is
634: to count the number of processes that are using a hash table,
635: by means of a counter \T busy/. The hash table can be thrown away when
636: \T busy/ is set to $0$. An important observation is that \T busy/
637: cannot be stored as part of the hash table, in the same way as
638: the variables \T size/, \T occ/ and \T bound/ above. The reason
639: for this is that a process can attempt to access the current
640: hash table by increasing its \T busy/ counter. However, just
641: before it wants to write the new value for \T busy/ it falls
642: asleep. When the process wakes up the hash table might have been
643: deleted and the process would be writing at a random place in
644: memory.
645:
646: This forces us to use separate arrays \T H/ and \T busy/ to store
647: the pointers to hash tables and the \T busy/ counters. There
648: can be $2P$ hash tables around, because each process can
649: simultaneously be accessing one hash table and attempting to
650: create a second one. The arrays below are shared variables.
651:
652: \begin {tab}
653: \>$\T H/:\B array /1\DOTS 2P \B\ of pointer to /\S Hashtable/$ ;\\
654: \>$\T busy/ :\B array /1\DOTS 2P \B\ of / \S Nat/$ ;\\
655: \>$\T prot/:\B array /1\DOTS 2P \B\ of / \S Nat/$ ;\\
656: \>$\T next/:\B\ array /1\DOTS 2P \B\ of /0\DOTS 2P$ .
657: \end {tab}
658: As indicated, we also need arrays \T prot/ and \T next/. The variable
659: $\T next/[i]$ points to the next hash table to which the
660: contents of hash table $\T H/[i]$ is being copied.
661: If $\T next/[i]$ equals $0$, this means that there is no next
662: hash table. The variable $\T prot/[i]$
663: is used to guard the variables $\T busy/[i]$, $\T next/[i]$ and
664: $\T H/[i]$ against being reused for a new table, before
665: all processes have discarded them.
666:
667: We use a shared variable \T currInd/ to hold the index
668: of the currently valid hash table:
669: \begin {tab}
670: \>$\T currInd/:1\DOTS 2P$ .
671: \end {tab}
672: Note however that after a process copies $\T currInd/$
673: to its local memory, other processes may create a new
674: hash table and change $\T currInd/$ to point to that one.
675:
676: It is assumed that initially $\T H/[1]$ is pointing to
677: some hash table. The other initial values of the shared
678: variables are given by
679: \begin{tab}
680: \> $ \T currInd/ = \T busy/[1] = \T prot/[1] = 1 $ ,\\
681: \> $\T H/[i] = \T busy/[i] =
682: \T prot/[i] = 0 $ \ for all $i\ne 1$ ,\\
683: \> $ \T next/[i] = 0 $ \ for all $i$.
684: \end{tab}
685:
686: \subsection{Primary procedures} \label{primary}
687:
688: We first provide the code for the primary procedures, which match
689: directly with the procedures in the interface. Every process has
690: a private variable
691: \begin{tab}
692: \>$\S index/:1\DOTS 2P$;
693: \end{tab}
694: containing what it regards as the currently active hash table.
695: At entry of each primary procedure,
696: it must be the case that the variable $\T H/[\S index/]$
697: contains valid information.
698: In section \ref{Mem}, we provide procedure \S getAccess/ with
699: the main purpose to guarantee this property.
700: When \S getAccess/ has been called, the system is obliged to
701: keep the hash table at \S index/ stored in memory, even if there
702: are no accesses to the hash table using any of the primary
703: procedures. A procedure \S releaseAccess/ is provided to
704: release resources, and it should be called whenever the
705: process will not access the hash table for some time.
706:
707: \subsubsection{Syntax}
708:
709: We use a syntax analogous to Modula-3 \cite{Har92}. We use $:=$ for
710: the assignment. We use the C--operations \T ++/ and
711: \T --/ for atomic increments and decrements.
712: The semicolon is a separator, not a terminator.
713: The basic control mechanisms are
714: \begin{tab}
715: \> \B loop .. end / is an infinite loop, terminated by
716: \B exit/ or \B return/\\
717: \> \B while .. do .. end / and \B repeat .. until .. / are
718: ordinary loops\\
719: \> \B if .. then .. \{elsif ..\} [else ..] end / is the
720: conditional\\
721: \> \B case .. end / is a case statement.
722: \end{tab}
723: Types are slanted and start with a capital. Shared variables
724: and shared data elements are in typewriter font. Private variables
725: are slanted or in math italic.
726:
727: \subsubsection{The main loop}
728: We model the clients of the hash table in the following loop. This
729: is not an essential part of the algorithm, but it is needed in the
730: PVS description, and therefore provided here.
731: \begin {tab}
732: \>\B loop/\\
733: 0: \>\> $ \S getAccess/()$ ;\\
734: \>\>\B loop/\\
735: 1: \>\>\>$\S choose call; /\B case /call\ \B of /$\\
736: \>\>\>\> $(f,a)\ \B with /\ a\neq 0\rightarrow \S find/(a)$\\
737: \>\>\>\> $(d,a)\ \B with /\ a\neq 0\rightarrow \S delete/(a)$\\
738: \>\>\>\> $(i,v)\ \B with /\ v\neq \B null/\rightarrow
739: \S insert/(v)$\\
740: \>\>\>\> $(a,v)\ \B with /\ v\neq \B null/\rightarrow
741: \S assign/(v)$\\
742: \>\>\>\> $(r)\ \rightarrow \S releaseAccess/(\S index/);\ \B exit/$\\
743: \>\>\>\B end/\\
744: \>\>\B end/\\
745: \>\B end/
746: \end{tab}
747: The main loop shows that each process repeatedly invokes its four
748: principle operations with correct arguments in an arbitrary, serial
749: manner. Procedure \S getAccess/ has to provide the client with a
750: protected value for \S index/. Procedure \S releaseAccess/
751: releases this value and its protection. Note that \B exit/ means
752: a jump out of the inner loop.
753:
754: \subsubsection{Procedure \S find/}
755:
756: Finding an address in a hash table with open addressing requires
757: a linear search over the possible hash keys until the address or
758: an empty slot is found. The kernel of procedure \S find/ is
759: therefore:
760: \begin {tab}
761: \>\+ $ n:= 0 $ ;\\
762: $ \B repeat /\; r:=h.\T table/[\S key/(a, l, n)] \;;\quad
763: n\T ++/ $ ;\\
764: $ \B until / \; r= \B null/\Lor a = \S ADR/(r) $ ;
765: \end{tab}
766: The main complication is that, when the process encounters an entry
767: \B done/ (i.e. \S old/(\B null/)), it has to join the migration
768: activity by calling \S refresh/.
769:
770: Apart from a number of special commands, we group statements
771: such that at most one shared variable is accessed and label these
772: `atomic' statements with a number. The labels are chosen identical
773: to the labels in the PVS code, and therefore not completely
774: consecutive.
775:
776: In every execution step, one of the processes proceeds from
777: one label to a next one. The steps are thus treated as
778: atomic. The atomicity of steps that refer to shared variables
779: more than once is emphasized by enclosing them in angular
780: brackets. Since procedure calls only modify private control data,
781: procedure headers are not always numbered themselves, but their bodies
782: usually have numbered atomic statements.
783: %\newpage
784: \begin {tab}
785: \>$ \B proc /\S find/ (a:\S Address/\setminus\{0\}) :
786: \S Value/= $\\
787: \>\>\B local/ $ r:\S EValue/$ ; $ n,l:\S Nat/\;;\;
788: h:\B pointer to /\S Hashtable/$ ;\\
789: 5: \>\> $h:=\T H/[\S index/]\;;\; n:=0 \;;\;\{ \S cnt/:=0\}$ ;\\
790: 6: \>\> $l:=h.\T size/$ ;\\
791: \>\>\B repeat/\\
792: 7: \>\>\>\la~$r:=h.\T table/[\S key/(a, l, n)] $ ;\\
793: \>\>\>~~$\{ \B\ if /r= \B null/\Lor a=\S ADR/(r)\B\ then /\;
794: \S cnt/\T ++/\;;\;\R (fS)/ \;\B\ end /\}\;\ra $ ;\\
795: 8: \>\>\> \B if / $r=\B done/\;\B\ then /$\\
796: \>\>\>\> $ \S refresh/()$ ;\\
797: 10: \>\>\>\>$ h:=\T H/[\S index/]\;;\; n:=0$ ;\\
798: 11: \>\>\>\>$l:=h.\T size/$ ;\\
799: \>\>\>$ \B else /\; n\T ++/\; \B\ end/$ ;\\
800: 13: \>\>\B until/ $r= \B null/\Lor a=\S ADR/(r) $ ;\\
801: 14: \>\B return/ $\S val/(r)$ .
802: \end{tab}
803:
804: In order to prove correctness, we add between braces
805: instructions that only modify auxiliary variables, like the
806: specification variables \T X/ and $rS$ and other auxiliary
807: variables to be introduced later.
808: The part between braces is comment for the implementation, it
809: only serves in the proof of correctness. The private auxiliary
810: variable \S cnt/ of type \S Nat/ counts the number of times
811: (fS) is executed and serves to prove that (fS) is executed
812: precisely once in every call of \S find/.
813:
814: This procedure matches the code of an ordinary find in a hash table
815: with open addressing, except for the code at the
816: condition $r=\B done/$. This code is needed for the case that
817: the value at address $a$ has been copied, in which case the new
818: table must be located. Locating the new table is carried out
819: by the procedure \S refresh/, which is discussed in Section
820: \ref{Mem}. In line 7, the accessed hash table should be
821: valid (see invariants \S fi4/ and \S He4/ in Appendix A).
822: After \S refresh/ the local variables $n$, $h$ and
823: $l$ must be reset, to restart the search in the new hash table.
824: If the procedure terminates, the specifying atomic command (fS)
825: has been executed precisely once (see invariant \S Cn1/) and the
826: return values of the specification and the implementation are equal
827: (see invariant \S Co1/). If the operation succeeds,
828: the return value must be a valid entry currently associated with
829: the given address in the current hash table. It is not evident but
830: it has been proved that the linear search of the process executing
831: \S find/ cannot be violated by other processes, i.e. no other
832: process can \S delete/, \S insert/, or \S rewrite/ an entry
833: associated with the same address (as what the process is looking
834: for) in the region where the process has already searched.
835:
836: We require that every valid hash table contains at least one entry
837: \B null/ or \B done/. Therefore, the local variable $n$ in the
838: procedure \S find/ never goes beyond the size of the hash table
839: (see invariants \S Cu1/, \S fi4/, \S fi5/ and axiom \S Ax2/).
840: When the \T bound/ of the new hash table is tuned properly before
841: use (see invariants \S Ne7/, \S Ne8/),
842: the hash table will not be updated too frequently,
843: and termination of the procedure \S find/ can be guaranteed.
844:
845: \subsubsection{Procedure \S delete/}
846:
847: To some extent, deletion is similar to finding. Since $r$ is a
848: local variable to the procedure \S delete/, we regard 18a and 18b
849: as two parts of atomic instruction 18.
850: If the entry is found in the table, then at line 18b this entry
851: is overwritten with the designated element \B del/.
852:
853: %\newpage
854: \begin {tab}
855: \> $ \B proc /\S delete/ (a:\S Address/\setminus\{0\}) :
856: \S Bool/ = $\\
857: \>\>\B local/ $ r:\S EValue/\;;\; k,l,n:\S Nat/ $ ;\\
858: \>\>\> $ h:\B pointer to /\S Hashtable/\;;\;\S suc/:\S Bool/$ ;\\
859: 15: \>\> $h:=\T H/[\S index/]\;;\;\S suc/:=\; \false\;;\;
860: \{\S cnt/:=0\} $ ;\\
861: 16: \>\>$l:=h.\T size/\;;\; n:=0$ ;\\
862: \>\>\B repeat/\\
863: 17: \>\>\> $k:=\S key/(a, l, n) $ ;\\
864: \>\>\> \la~$ r:=h.\T table/[k] $ ;\\
865: \>\>\>~~$\{\;\B if /r=\B null/\;\B\ then /\;
866: \S cnt/\T ++/\;;\; \R (dS) /\B\ end /\}\;\ra $ ;\\
867: 18a: \>\>\> $ \B if /\;\S oldp/(r)\;\B\ then / $\\
868: \>\>\>\> $ \S refresh/()$ ;\\
869: 20: \>\>\>\> $ h:=\T H/[\S index/]$ ; \\
870: 21: \>\>\>\> $ l:=h.\T size/\;;\; n:=0$ ;\\
871: \>\>\> $ \B elsif / \; a=\S ADR/(r)\;\B\ then / $\\
872: 18b:\>\>\>\> \la~$ \B if /\; r=h.\T table/[k] \;\B\ then /$\\
873: \>\>\>\>\>\>~~$\S suc/:= \true \;;\; h.\T table/[k] :=\B del/ $ ; \\
874: \>\>\>\>\>\>~~$\{\; \S cnt/\T ++/\;;\;\R (dS) /\;;\;
875: \T Y/[k] :=\B del/\ \}$\\
876: \>\>\>\>~~\B end /\ra\ ;\\
877: \>\>\> $\B else /\; n\T++/ \;\B\ end/ $ ; \\
878: \>\> $ \B until /\; \S suc/ \Lor r = \B null/ $ ;\\
879: 25: \>\> $ \B if /\; \S suc/\; \B\ then /\;
880: h.\T dels/ \T ++/\;\B\ end/$ ;\\
881: 26: \> \B return/ \S suc/ .
882: \end{tab}
883:
884: The repetition in this procedure has two ways to terminate.
885: Either deletion fails with $r=\B null/$ in 17, or deletion succeeds
886: with $r=h.\T table/[k]$ in 18b. In the latter case, we have in one
887: atomic statement a double access of the shared variable
888: $h.\T table/[k]$. This is a so-called compare\&swap instruction.
889: Atomicity is needed here to preclude interference. The specifying
890: command (dS) is executed either in 17 or in 18b, and it is executed
891: precisely once (see invariant \S Cn2/), since in 18b the guard
892: $a=\S ADR/(r)$ implies $r\ne\B null/$ (see invariant
893: \S de1/ and axiom \S Ax1/).
894:
895: In order to remember the address from the value rewritten
896: to \B done/ after the value is
897: being copied in the procedure \S moveContents/, in 18, we
898: introduce a new auxiliary shared variable \T Y/ of type array
899: of \S EValue/, whose contents
900: equals the corresponding contents of the current hash table
901: almost everywhere except that the values it contains are not
902: tagged as \S old/ or rewritten as \B done/ (see invariants
903: \S Cu9/, \S Cu10/).
904:
905: Since we postpone the increment of \S h/.\T dels/ until line 25,
906: the field \T dels/ is a lower bound of the number of positions
907: deleted in the hash table (see invariant \S Cu4/).
908:
909: \subsubsection{Procedure \S insert/}
910:
911: The procedure for insertion in the table is given below.
912: Basically, it is the standard algorithm for insertion in a
913: hash table with open addressing. Notable is line 28 where
914: the current process finds that the current hash table too full,
915: and orders a new table to be made.
916: We assume that $h.\T bound/$ is a number less than
917: $h.\T size/$ (see invariant \S Cu3/), which is tuned for optimal
918: performance.
919:
920: Furthermore, in line 35, it can be detected that values in the
921: hash table have been marked \S old/, which is a sign that
922: hash table $h$ is outdated, and the new hash table must
923: be located to perform the insertion.
924: \begin {tab}
925: \>$ \B proc /\S insert/ (v:\S Value/\setminus\{\B null/\}) :
926: \S Bool/ = $\\
927: \>\> $ \B local / r:\S EValue/\;;\; k,l,n:\S Nat/\;;\;
928: h:\B pointer to /\S Hashtable/$ ;\\
929: \>\>\> $\S suc/:\S Bool/\;;\; a:\S Address/:= \S ADR/(v) $ ;\\
930: 27: \>\>$h:=\T H/[\S index/] \;;\; \{\S cnt/:=0\} $ ;\\
931: 28: \>\>\B if/ $h.\T occ/ > h.\T bound/\B\ then /$\\
932: \>\>\> $ \S newTable/()$ ;\\
933: 30: \>\>\> $h:=\T H/[\S index/]\; \B\ end/$ ;\\
934: 31: \>\> $ n:=0\;;\; l:=h.\T size/\;;\; \S suc/:= \false$ ;\\
935: \>\> \B repeat /\\
936: 32: \>\>\>$ k:=\; \S key/(a,l,n) $ ; \\
937: 33: \>\>\>\la~$ r:=h.\T table/[k] $ ; \\
938: \>\>\>~~$ \{\;\B if /\;a=\S ADR/(r)\;
939: \B\ then /\; \S cnt/\T ++/\;;\;\R\ (iS) /\B\ end /\}\;\ra $ ;\\
940: 35a: \>\>\>$ \B if /\;\S oldp/(r)\; \B\ then/ $ \\
941: \>\>\>\> $ \S refresh/()$ ;\\
942: 36: \>\>\>\> $h:=\T H/[\S index/]$ ;\\
943: 37: \>\>\>\> $n:=0\;;\; l:=h.\T size/$ ;\\
944: \>\>\> $ \B elsif / \; r = \B null/ \B\ then /$\\
945: 35b: \>\>\>\> \la~$ \B if /\; h.\T table/[k] = \B null/
946: \;\B\ then/$\\
947: \>\>\>\>\> $ \S suc/:=\true \;;\; h.\T table/[k] :=v $ ; \\
948: \>\>\>\>\> $ \{\; \S cnt/\T ++/\;;\;\R (iS)/\;;\;
949: \T Y/[k] :=v\ \} $ \\
950: \>\>\>\>~~\B end /\ra\ ;\\
951: \>\>\> $\B else /\; n\T ++/\; \B\ end / $ ;\\
952: \>\> $ \B until /\;\S suc/\Lor a=\S ADR/(r)$ ;\\
953: 41: \>\> $ \B if /\; \S suc/\; \B\ then /\;
954: h.\T occ/ \T ++/\;\B\ end/$ ;\\
955: 42: \> $ \B return /\; \S suc/$ .
956: \end{tab}
957:
958: Instruction 35b is a version of compare\&swap. Procedure \S insert/
959: terminates successfully when the insertion to an empty slot is
960: completed, or it fails when there already exists an entry with the
961: given address currently in the hash table (see invariant \S Co3/ and
962: the specification of \S insert/).
963:
964: \subsubsection{Procedure \S assign/}
965:
966: Procedure \S assign/ is almost the same as \S insert/ except that
967: it rewrites an entry with a given value even when the associated
968: address is not empty. We provide it without further comments.
969: %\newpage
970: \begin {tab}
971: \>$ \B proc /\S assign/ (v:\S Value/\setminus\{\B null/\})
972: \ =$\\
973: \>\>\B local/ $ r:\S EValue/\;;\; k,l,n:\S Nat/\;;\;
974: h:\B pointer to /\S Hashtable/ $ ;\\
975: \>\>\> $ \S suc/:\S Bool/\;;\; a:\S Address/:=\S ADR/(v) $ ;\\
976: 43: \>\>$h:=\T H/[\S index/]\;;\; \S cnt/:=0$;\\
977: 44: \>\> $\B if /\; h.\T occ/> h.\T bound/\;\B\ then /$\\
978: \>\>\> $ \S newTable/()$ ;\\
979: 46: \>\>\> $ h:=\T H/[\S index/]\;\B\ end/$ ;\\
980: 47: \>\> $ n:=0 \;;\; l:=h.\T size/\;;\; \S suc/:= \false $ ;\\
981: \>\>\B repeat/\\
982: 48: \>\>\> $ k:=\; \S key/(a,l,n)$ ;\\
983: 49: \>\>\> $ r:=h.\T table/[k]$ ;\\
984: 50a: \>\>\> $ \B if /\; \S oldp/(r) \;\B\ then/ $\\
985: \>\>\>\> $ \S refresh/()$ ;\\
986: 51: \>\>\>\> $ h:=\T H/[\S index/]$ ;\\
987: 52: \>\>\>\> $n:=0\;;\; l:=h.\T size/$ ;\\
988: \>\>\> $ \B elsif /\; r=\B null/\Lor a=\S ADR/(r) \;
989: \B\ then /$\\
990: 50b: \>\>\>\> \la~$\B if /\;h.\T table/[k] = r\;\B\ then/$\\
991: \>\>\>\>\>$ \S suc/:=\true \;;\;
992: h.\T table/[k] := v\;;\; $\\
993: \>\>\>\>\> $\{\; \S cnt/\T ++/\;;\; \R\ (aS) /;\ \T Y/[k]:=v\ \}$ \\
994: \>\>\>\>~~\B end /\ra \\
995: \>\>\>$ \B else /\; n\T ++/\;\B\ end/$ ;\\
996: \>\> $ \B until /\S suc/ $ ;\\
997: 57: \>\> $ \B if /\; r=\B null/\;\B\ then /\;
998: h.\T occ/\T ++/\;\B\ end/ $ ; \\
999: \>\B end/.
1000: \end{tab}
1001:
1002: \subsection {Memory management and concurrent migration}
1003: \label{Mem}
1004:
1005: In this section, we provide the public procedures \S getAccess/
1006: and \S releaseAccess/ and the auxiliary procedures \S refresh/
1007: and \S newTable/ which are responsible for allocation and
1008: deallocation. We begin with the treatment of memory by providing
1009: a model of the heap.
1010:
1011: \subsubsection {The model of the heap}
1012: We \emph{model} the \T Heap/ as an infinite array of
1013: hash tables, declared and initialized in the following way:
1014: \begin{tab}
1015: \>\+ $\T Heap/:\B\ array /\S Nat/\B\ of /\S Hashtable/:=([\S Nat/]\bot)$ ;\\
1016: $ \T H/_-\T index/:\S Nat/:= 1 $ .
1017: \end{tab}
1018: So, initially, $\T Heap/[i] = \bot$ for all indices $i$.
1019: The indices of array \T Heap/ are the pointers to hash tables. We
1020: thus simply regard \B pointer to/ \S Hashtable/ as a synonym of
1021: \S Nat/.
1022: Therefore, the notation $h.\T table/$ used elsewhere in the paper
1023: stands for $\T Heap/[h].\T table/$. Since we reserve 0 (to be
1024: distinguished from the absent hash table $\bot$ and the absent
1025: value \B null/) for the null pointer (i.e. $\T Heap/[0]=\bot$,
1026: see invariant \S He1/), we initialize \T H/$_-$\T index/, which is
1027: the index of the next hash table, to be 1 instead of 0. Allocation
1028: of memory is modeled in
1029: \begin{tab}
1030: \>\+\+ $ \B proc /\S allocate/(s, b:\S Nat/): \S Nat/ =$ \\
1031: \la~$\T Heap/ [\T H/_-\T index/]:=\R\ blank hash table with /
1032: \T size/= s, \T bound/=b,$\\
1033: \>\>\>\> $ \T occ/=\T dels/=0$ ;\\
1034: ~~$\T H/_-\T index/\T ++/\ \ra $ ;\-\\
1035: $\B return /\T H/_-\T index/ $ ;
1036: \end{tab}
1037: We assume that $\S allocate/$ sets all values in the hash table
1038: $\T Heap/[\T H/_-\T index/]$ to $\B null/$, and also sets its fields
1039: $\T size/$ and $\T bound/$ as specified.
1040: The variables \T occ/ and \T dels/ are set to 0 because
1041: the hash table is completely filled with the value \B null/.
1042:
1043: Deallocation of hash tables is modeled by
1044: \begin{tab}
1045: \>\+ $ \B proc /\S deAlloc/(h:\S Nat/) =$ \\
1046: \>\la~$ \B assert /\T Heap/[h]\ne\bot\;;\quad
1047: \T Heap/[h]:=\bot\ \ra $ \\
1048: \B end/ .
1049: \end{tab}
1050: The \B assert/ here indicates the obligation to prove
1051: that \S deAlloc/ is called only for allocated memory.
1052:
1053: \subsubsection{Procedure \S getAccess/}
1054: The procedure \S getAccess/ is defined as follows.
1055: %\newpage
1056: \begin {tab}
1057: \>$\B proc /\S getAccess/() = $ \\
1058: \>\>$ \B loop/$\\
1059: 59: \>\>\> $ \S index/ :=\; \T currInd/$;\\
1060: 60: \>\>\> $ \T prot/[\S index/]\T ++/$ ;\\
1061: 61: \>\>\> $ \B if / \; \S index/ =\T currInd/\; \B\ then /$\\
1062: 62: \>\>\>\> $ \T busy/[\S index/]\T++/ $ ;\\
1063: 63: \>\>\>\> $ \B if /\; \S index/ =\T currInd/\;
1064: \B\ then return/ $ ;\\
1065: \>\>\>\> $ \B else /\; \S releaseAccess/(\S index/)\;\B\ end/$ ;\\
1066: 65: \>\>\> $ \B else /\;\T prot/[\S index/]\T --/\;\B\ end/$ ;\\
1067: \>\>\B end/\\
1068: \>\B end/.
1069: \end {tab}
1070: This procedure is a bit tricky. When the process reaches line 62,
1071: the \S index/ has been protected not to be used for creating a
1072: new hash table in the procedure \S newTable/ (see invariants \S pr2/,
1073: \S pr3/ and \S nT12/).
1074:
1075: The hash table pointer $\T H/[\S index/]$ must contain the valid
1076: contents after the procedure \S getAccess/ returns (see invariants
1077: \S Ot3/, \S He4/). So, in line 62, \T busy/ is increased,
1078: guaranteeing that the hash table will not inadvertently be destroyed
1079: (see invariant \S bu1/ and line 69).
1080: Line 63 needs to check the \S index/ again in case that instruction
1081: 62 has the precondition that the hash table is not valid. Once some
1082: process gets hold of one hash table after calling \S getAccess/, no
1083: process can throw it away until the process releases it (see
1084: invariant \S rA7/).
1085:
1086: \subsubsection{Procedure \S releaseAccess/}\label{deallocate}
1087: The procedure \S releaseAccess/ is given by
1088: \begin {tab}
1089: \>$\B proc /\S releaseAccess/(i:1\DOTS 2P) = $\\
1090: \>\>\B local/ $h:\B pointer to /\S Hashtable/$ ;\\
1091: 67: \>\>$ \S h/ :=\; \T H/[i] $ ;\\
1092: 68: \>\>$ \T busy/[i]\T --/$ ;\\
1093: 69: \>\>$\B if /\;\S h/\ne 0\Land \T busy/[i] = 0\; \B\ then/$\\
1094: 70: \>\>\>$\la~\B if /\T H/[i] = h\; \B\ then /\;\T H/[i]:= 0$ ; \ra\\
1095: 71: \>\>\>\>$ \S deAlloc/(h)$ ;\\
1096: \>\>\>~~\B end/ ;\\
1097: \>\> \B end/ ;\\
1098: 72: \>\> $ \T prot/[i]\T --/$ ;\\
1099: \>\B end/.
1100: \end {tab}
1101: The test $h\ne 0$ at 69 is necessary since it is possible that $h=0$ at the
1102: lines 68 and 69. This occurs e.g. in the following scenario.
1103: Assume that process $p$ is at line 62 with $\S index/ \ne\T currInd/$, while
1104: the number $i=\S index/$ satisfies $\T H/[i] = 0$ and $\T busy/[i]=0$.
1105: Then process $p$ increments $\T busy/[i]$, calls $\S releaseAccess/(i)$,
1106: and arrives at 68 with $h=0$.
1107:
1108: Since \S deAlloc/ in line 71 accesses a shared variable, we have
1109: separated its call from 70. The counter $\T busy/[i]$ is used to
1110: protect the hash table from premature deallocation. Only if \T
1111: busy/[i]=0, \T H/[i] can be released. The main problem of the design
1112: at this point is that it can happen that several processes
1113: concurrently execute \S releaseAccess/ for the same value of $i$, with
1114: interleaving just after the decrement of $\T busy/[i]$. Then they all
1115: may find $\T busy/[i]=0$. Therefore, a bigger atomic command is needed
1116: to ensure that precisely one of them sets $\T H/[i]$ to $0$ (line 70)
1117: and calls \S deAlloc/. Indeed, in line 71, \S deAlloc/ is called only
1118: for allocated memory (see invariant \S rA3/). The counter $\T
1119: prot/[i]$ can be decreased since position $i$ is no longer used by
1120: this process.
1121:
1122: \subsubsection{Procedure \S newTable/}
1123:
1124: When the current hash table has been used for some time, some
1125: actions of the processes may require replacement of this hash
1126: table. Procedure \S newTable/ is called when the number of
1127: occupied positions in
1128: the current hash table exceeds the \T bound/ (see lines 28, 44).
1129: Procedure \S newTable/ tries to allocate a new hash table as the
1130: successor of the current one.
1131: If several processes call \S newTable/ concurrently, they need to
1132: reach consensus on the choice of an index for the next hash table
1133: (in line 84). A newly allocated hash table that will not be used
1134: must be deallocated again.
1135: %\newpage
1136: \begin {tab}
1137: \>$\B proc /\S newTable/() = $ \\
1138: \>\>\B local/ $ i:1\DOTS 2P\;;\;b , bb:\S Bool/$ ;\\
1139: 77: \>\> $ \B while/\; \T next/[\S index/] = 0\; \B\ do/ $\\
1140: 78: \>\>\> $ \B choose /i \in 1\DOTS 2P$ ;\\
1141: \>\>\> \la~$b:=(\T prot/[i] = 0) $ ;\\
1142: \>\>\>~~$ \B if /\;b\;\B\ then /
1143: \T prot/[i]:=1\;\B\ end / \ra $ ;\\
1144: \>\>\> $\B if /\;b\;\B\ then / $ \\
1145: 81: \>\>\>\> $ \T busy/[i]:=1$ ;\\
1146: 82: \>\>\>\> $\B choose /
1147: \S bound/ > \T H/[\S index/].\T bound/-\T H/[\S index/].\T dels/+2P $ ;\\
1148: \>\>\>\> $\B choose /\S size/> \S bound/+2P $ ;\\
1149: \>\>\>\>$\T H/[i] :=\S allocate/(\S size/, \S bound/)\;; $\\
1150: 83: \>\>\>\> $ \T next/[i]:=0 $ ;\\
1151: 84: \>\>\>\> \la~$ bb:=(\T next/[\S index/] = 0)$ ;\\
1152: \>\>\>\>~~$ \B if /\; bb\; \B\ then /\;
1153: \T next/[\S index/] :=i\ \B\ end /\ra $ ;\\
1154: \>\>\>\>$ \B if /\; \neg bb\; \B\ then /\;
1155: \S releaseAccess/(i)\; \B\ end /$ ;\\
1156: \>\> \B end end/ ;\\
1157: \>\>$\S refresh/()$ ;\\
1158: \>\B end/ .
1159: \end {tab}
1160: In command 82, we allocate a new blank hash table (see invariant
1161: \S nT8/), of which the \T bound/ is set greater than
1162: $\T H/[\S index/].\T bound/-\T H/[\S index/].\T dels/+2P$
1163: in order to avoid creating a too small hash table (see invariants
1164: \S nT6/, \S nT7/).
1165:
1166: We require the \T size/ of a hash table to be more than
1167: $\T bound/+2P$ because of the following scenario: $P$ processes find
1168: ``$h.\T occ/>h.\T bound/$'' at line 28 and call \S newtable/,
1169: \S refresh/, \S migrate/, \S moveContents/ and \S moveElement/ one
1170: after the other.
1171: After moving some elements, all processes but process $p$ sleep at
1172: line 126 with $b_{\it mE}=\true$ ($b_{\it mE}$ is the local variable
1173: $b$ of procedure \S moveElement/). Process $p$ continues the
1174: migration and updates the new current index when the migration
1175: completes. Then, process $p$ does several insertions to let the
1176: \T occ/ of the current hash table reach one more than its \T bound/.
1177: Just at that moment, $P-1$ processes wake up, increase the \T occ/
1178: of the current hash table to be $P-1$ more, and return to line 30.
1179: Since $P-1$ processes insert different values in the hash table,
1180: after $P-1$ processes finish their insertions, the \T occ/ of the
1181: current hash table reaches $2P-1$ more than its \T bound/.
1182:
1183: It may be useful to make \T size/ larger than $\T bound/ + 2P $ to
1184: avoid too many collisions, e.g. with a constraint
1185: $\T size/\geq\alpha\cdot\T bound/$ for some $\alpha >1$.
1186: If we did not introduce \T dels/, every migration would force the
1187: sizes to grow, so that our hash table would require unbounded space
1188: for unbounded life time. We introduced \T dels/ to avoid this.
1189:
1190: Strictly speaking, instruction 82 inspects one shared variable,
1191: $\T H/[\S index/]$, and modifies three other shared variables, viz.
1192: $\T H/[i]$, $\T Heap/[\T H/_-\T index/]$, and $\T H/_-\T index/$.
1193: In general, we split such multiple shared variable accesses in
1194: separate atomic commands. Here the accumulation is harmless, since
1195: the only possible interferences are with other allocations at line
1196: 82 and deallocations at line 71. In view of the invariant \S Ha2/,
1197: all deallocations are at pointers $h<\T H/_-\T index/$.
1198: Allocations do not interfere because they contain the
1199: increment $\T H/_-\T index/$++ (see procedure \S allocate/).
1200:
1201: The procedure \S newTable/ first searches for a free index $i$, say
1202: by round robin. We use a nondeterministic choice.
1203: Once a free index has been found, a hash table is allocated and
1204: the index gets an indirection to the allocated address. Then the
1205: current index gets a \T next/ pointer to the new
1206: index, unless this pointer has been set already.
1207:
1208: The variables $\T prot/[i]$ are used primarily as
1209: counters with atomic increments and
1210: decrements. In 78, however, we use an atomic test-and-set
1211: instruction.
1212: Indeed, separation of this instruction in two atomic
1213: instructions is incorrect, since that would allow
1214: two processes to grab the same index $i$ concurrently.
1215:
1216: \subsubsection{Procedure \S migrate/}
1217: After the choice of the new hash table, the procedure \S migrate/
1218: serves to transfer the contents in the current hash table to the new
1219: hash table by calling a procedure \S moveContents/ and to update the
1220: current hash table pointer afterwards. Migration is complete when at
1221: least one of the (parallel) calls to \S migrate/ has terminated.
1222:
1223: \begin {tab}
1224: \>$ \B proc /\S migrate/() = $ \\
1225: \>\>\B local/ $i:0\DOTS 2P$; $h:\B pointer to /\S Hashtable/\;;\;
1226: b:\S Bool/$ ;\\
1227: 94: \>\>$ i:=\T next/[\S index/]$;\\
1228: 95: \>\> $ \T prot/[i]\T ++/$ ;\\
1229: 97: \>\>$ \B if /\;\S index/\ne\T currInd/\;\B\ then /$\\
1230: 98: \>\>\>$ \T prot/[i]\T --/$ ;\\
1231: \>\> \B else / \\
1232: 99: \>\>\>$ \T busy/[i] \T ++/$ ;\\
1233: 100: \>\>\>$h:=\T H/[i]$ ;\\
1234: 101: \>\>\>$ \B if /\; \S index/=\T currInd/\;\B\ then / $\\
1235: \>\>\>\>$ \S moveContents/(\T H/[\S index/], h) $ ;\\
1236: 103: \>\>\>\>\la~$b:=(\T currInd/=\S index/)$ ;\\
1237: \>\>\>\>~~$\B if /\; b \;\B\ then /\;\T currInd/:=i$ ;
1238: \ $\{\T Y/:=\T H/[\S i/].\T table/\ \}$\\
1239: \>\>\>\>~~$\B end /\ra$ ;\\
1240: \>\>\>\>$ \B if /\; b\; \B\ then /$ \\
1241: 104: \>\>\>\>\>$ \T busy/[\S index/] \T --/$ ;\\
1242: 105: \>\>\>\>\>$ \T prot/[\S index/] \T --/$ ;\\
1243: \>\>\> \B end end/ ;\\
1244: \>\>\> $\S releaseAccess/(i)$ ;\\
1245: \>\B end end /.
1246: \end {tab}
1247:
1248: According to invariants \S mi4/ and \S mi5/, it is an invariant that
1249: $i=\T next/(\S index/)\neq 0$ holds after instruction 94.
1250:
1251: Line 103 contains a compare\&swap instruction to update the current
1252: hash table pointer when some process finds that the migration is
1253: finished while \T currInd/ is still identical to its \S index/, which
1254: means that $i$ is still used for the next current hash table (see
1255: invariant \S mi5/). The increments of $\T prot/[i]$ and $\T busy/[i]$
1256: here are needed to protect the next hash table. The decrements serve
1257: to avoid memory loss.
1258:
1259: \subsubsection{Procedure \S refresh/}
1260: In order to avoid that a delayed process starts migration of an old
1261: hash table, we encapsulate \S migrate/ in \S refresh/ in the
1262: following way.
1263: \begin {tab}
1264: \>$ \B proc /\S refresh/() = $\\
1265: 90: \>\>$ \B if /\; \S index/\ne\T currInd/\; \B\ then/ $\\
1266: \>\>\>$ \S releaseAccess/(\S index/) $ ;\\
1267: \>\>\>$ \S getAccess/() $ ;\\
1268: \>\>$ \B else /\;\S migrate/()\;\B\ end/$ ;\\
1269: \>\B end/.
1270: \end {tab}
1271: When \S index/ is outdated, the process needs to call
1272: \S releaseAccess/ to abandon its hash table and \S getAccess/ to acquire
1273: the present pointer to the current hash table.
1274: Otherwise, the process can join the migration.
1275:
1276: \subsubsection{Procedure \S moveContents/}
1277: Procedure \S moveContents/ has to move the contents of
1278: the current table to the next current table. All processes that
1279: have access to the table, may also participate in
1280: this migration. Indeed, they cannot yet use the new table (see invariants
1281: \S Ne1/ and \S Ne3/).
1282: We have to take care that delayed actions on the current
1283: table and the new table are carried out or abandoned correctly
1284: (see invariants \S Cu1/ and \S mE10/).
1285: Migration requires that every value in the current table
1286: be moved to a unique position in the new table (see invariant \S Ne19/).
1287:
1288: Procedure \S moveContents/ uses a private variable \S toBeMoved/
1289: that ranges over sets of locations. The procedure is given by
1290: %\newpage
1291: \begin {tab}
1292: \>$\B proc /\S moveContents/
1293: (\S from/, \S to/: \B pointer to /\S Hashtable/)=$\\
1294: \>\>\B local/ $i:\S Nat/\;;\;b:\S Bool/\;;\; v:\S EValue/ \;;\;
1295: \S toBeMoved/ : \B set/\ \B of/\ \S Nat/$ ;\\
1296: \>\> $ \S toBeMoved/:= \{ 0,\ldots, \S from/.\T size/-1\}$ ;\\
1297: 110: \>\>$ \B while /\; \T currInd/ = \S index/\wedge
1298: \S toBeMoved/ \ne \emptyset \;\B\ do / $\\
1299: 111: \>\>\>\B choose/ $i\in\S toBeMoved/$ ;\\
1300: \>\>\> $ v:=\S from/.\T table/[i]$ ;\\
1301: \>\>\> $ \B if /\; v=\B done/\; \B\ then/$\\
1302: 112: \>\>\>\>$\S toBeMoved/:=\S toBeMoved/-\{i\}$ ;\\
1303: \>\>\>\B else/\\
1304: 114: \>\>\>\>\la~$b:=(v=\S from/.\T table/[i])$ ;\\
1305: \>\>\>\>~~\B if/ $b$ \B then/ $\S from/.\T table/[i]:=
1306: \S old/(\S val/(v))\;\B\ end / \ra$ ;\\
1307: \>\>\>\>\B if/ $b$ \B then/\\
1308: 116: \>\>\>\>\> $ \B if /\; \S val/(v)\ne \B null/\;
1309: \B\ then /\; \S moveElement/(\S val/(v),\S to/)\;\B\ end/$ ;\\
1310: 117: \>\>\>\>\>$\S from/.\T table/[i]:=\B done/ $ ;\\
1311: 118: \>\>\>\>\>$\S toBeMoved/:=\S toBeMoved/-\{i\}$ ;\\
1312: \>\>\B end end end /;\\
1313: \>\B end/ .
1314: \end {tab}
1315:
1316: Note that the value is tagged as outdated before it is copied
1317: (see invariant \S mC11/).
1318: After tagging, the value cannot be deleted or assigned until the
1319: migration has been completed. Tagging must be done atomically,
1320: since otherwise an interleaving deletion may be lost. When indeed
1321: the value has been copied to the new hash table, it becomes
1322: \B done/ in the old hash table in line 117. This has the effect
1323: that other processes need not wait for this process to complete
1324: procedure \S moveElement/, but can help with the migration of this
1325: value if needed.
1326:
1327: Since the address is lost after being rewritten to \B done/, we
1328: had to introduce the shared auxiliary hash table \T Y/ to remember
1329: its value for the proof of correctness. This could have been avoided
1330: by introducing a second tagging bit, say for ``very old''.
1331:
1332: The processes involved in the same migration should not
1333: use the same strategy for choosing $i$ in line 111,
1334: since it is advantageous that \S moveElement/ is called often with
1335: different values. They may exchange information: any of
1336: them may replace its set \S toBeMoved/ by the intersection
1337: of that set with the set \S toBeMoved/ of another one.
1338: We do not give a preferred strategy here, one can refer to
1339: algorithms for the {\it write-all} problem \cite{Jan00,KS97}.
1340:
1341: \subsubsection{Procedure \S moveElement/}
1342:
1343: The procedure \S moveElement/ moves a value
1344: to the new hash table. Note that the value is tagged as
1345: outdated in \S moveContents/ before \S moveElement/ is called.
1346: %\newpage
1347: \begin {tab}
1348: \> $\B proc /\S moveElement/(v:\S Value/\setminus\{\B null/\},
1349: \S to/: \B pointer to /\S Hashtable/) = $ \\
1350: \>\>\B local/ $a:\S Address/\;;\; k,m,n:\S Nat/\;;\;
1351: w:\S EValue/\;;\; b:\S Bool/$ ;\\
1352: 120: \>\>$n:=0\;;\; b:=\false\;;\; a :=\S ADR/(v)\;;\;
1353: m:=\S to/.\T size/$ ;\\
1354: \>\>\B repeat /\\
1355: 121: \>\>\>$k:=\; \S key/(a,m,n)\;;\;
1356: w:=\S to/.\T table/[k] $ ;\\
1357: \>\>\>\B if/ $w=\B null/$ \B then/\\
1358: 123: \>\>\>\>\la~$b:=(\S to/.\T table/[k] = \B null/) $;\\
1359: \>\>\>\>~~$ \B if /\; b\; \B\ then /\; \S to/.\T table/[k] :=v\ \B\ end /\ra$ ;\\
1360: \>\>\>\B else/ $n\T ++/\;\B\ end/$ ;\\
1361: 125: \>\> $ \B until / \; b\Lor a=\S ADR/(w) \Lor
1362: \T currInd/ \ne \S index/ $ ;\\
1363: 126: \>\> $ \B if /\; b\; \B\ then /\; \S to/.\T occ/\T ++/\;\B\ end/$ \\
1364: \>\B end/ .
1365: \end {tab}
1366:
1367: The value is only allowed to be inserted once in the new hash table
1368: (see invariant \S Ne19/), since otherwise the main property of open
1369: addressing would be violated.
1370: In total, four situations can occur in the procedure moveElement:
1371: \begin{itemize}
1372: \item {the current location $k$ contains a value with a different
1373: address. The process increases $n$ to inspect the next location.}
1374: \item {the current location $k$ contains a value with the same
1375: address. This means that the value has already been copied to the
1376: new hash table, the process therefore terminates.}
1377: \item {the current location $k$ is an empty slot. The process inserts
1378: \S v/ and returns. If insertion fails, since another process filled
1379: the empty slot in between, the search is continued.}
1380: \item {when \S index/ happens to differ from \T currInd/,
1381: the entire migration has been completed.}
1382: \end{itemize}
1383:
1384: While the current hash table pointer is not updated yet,
1385: there exists at least one \B null/ entry in the new hash table
1386: (see invariants \S Ne8/, \S Ne22/ and \S Ne23/),
1387: hence the local variable $n$ in the
1388: procedure \S moveElement/ never goes beyond the size of the
1389: hash table (see invariants \S mE3/ and \S mE8/),
1390: and the termination is thus guaranteed.
1391:
1392: \section {Correctness (Safety)} \label{safety}
1393:
1394: In this section, we describe the proof of safety of the algorithm.
1395: The main aspects of safety are functional correctness, atomicity, and
1396: absence of memory loss.
1397: These aspects are formalized in eight invariants described in
1398: section \ref{safetymain}. To prove these invariants, we need many
1399: other invariants. These are listed in Appendix A. In section
1400: \ref{intuproof}, we sketch the verification of some of the invariants
1401: by informal means.
1402: In section \ref{pvs-model}, we describe how the theorem prover PVS is
1403: used in the verification. As exemplified in \ref{intuproof}, Appendix B
1404: gives the dependencies between the invariants.
1405:
1406: \B Notational Conventions./
1407: Recall that there are at most $P$ processes with process identifiers
1408: ranging from 1 up to $P$. We use $p$, $q$, $r$ to range over process
1409: identifiers, with a preference for $p$.
1410: Since the same program is executed by all processes, every private
1411: variable name of a process $\ne p$ is extended with the suffix ``.'' +
1412: ``process identifier''.
1413: We do not do this for process $p$. So, e.g., the value of a private
1414: variable $x$ of process $q$ is denoted by $x.q$, but the value of
1415: $x$ of process $p$ is just denoted by $x$. In particular, $pc.q$ is the
1416: program location of process $q$. It ranges over all integer labels used
1417: in the implementation.
1418:
1419: When local variables in different procedures have the same names,
1420: we add an abbreviation of the procedure name as a subscript to the name.
1421: We use the following abbreviations: \S fi/ for \S find/, \S del/ for
1422: \S delete/, \S ins/ for \S insert/, \S ass/ for \S assign/, \S gA/ for
1423: \S getAccess/, \S rA/ for \S releaseAccess/, \S nT/ for \S newTable/,
1424: \S mig/ for \S migrate/, \S ref/ for \S refresh/, \S mC/ for
1425: \S moveContents/, \S mE/ for \S moveElement/.
1426:
1427: In the implementation, there are several places where the same
1428: procedure is called, say \S getAccess/, \S releaseAccess/, etc.
1429: We introduce auxiliary private variables \S return/, local to such a
1430: procedure, to hold the return location. We add a procedure subscript
1431: to distinguish these variables according to the above convention.
1432:
1433: If $V$ is a set, $\sharp V$ denotes
1434: the number of elements of $V$. If $b$ is a boolean, then $\sharp b =0$
1435: when $b$ is false, and $\sharp b = 1$ when $b$ is true.
1436: Unless explicitly defined otherwise, we always (implicitly) universally
1437: quantify over addresses $a$, values $v$, non-negative integer numbers
1438: $k$, $m$, and $n$,
1439: natural number $l$, processes $p$, $q$ and $r$. Indices $i$ and $j$
1440: range over $[1,2P]$. We abbreviate \T H/(\T currInd/).\T size/ as
1441: \S curSize/.
1442:
1443: In order to avoid using too many parentheses, we use the usual binding
1444: order for the operators. We give ``$\wedge$'' higher priority than
1445: ``$\vee$''. We use parentheses whenever necessary.
1446:
1447: \subsection {Main properties}\label{safetymain}
1448:
1449: We have proved the following three safety properties of the algorithm.
1450: Firstly, the access procedures \S find/, \S delete/, \S insert/,
1451: \S assign/, are functionally correct. Secondly they are executed
1452: atomically. The third safety property is absence of memory loss.
1453:
1454: Functional correctness of \S find/, \S delete/, \S insert/ is the
1455: condition that the result of the implementation is the same as the
1456: result of the specification (fS), (dS), (iS). This is expressed by
1457: the required invariants:
1458: \begin{tab} %Correct1, Correct2, Correct3\\
1459: \S Co1:/ \>$ \S pc/=14 \Implies \S val/(r_{\it fi})=rS_{\it fi}$ \\
1460: \S Co2:/ \>$ \S pc/\in \{25,26\} \Implies
1461: suc_{\it del}=sucS_{\it del}$ \\
1462: \S Co3:/ \>$ \S pc/\in \{41,42\} \Implies
1463: suc_{\it ins}=sucS_{\it ins}$
1464: \end{tab}
1465:
1466: Note that functional correctness of \S assign/ holds trivially since it
1467: does not return a result.
1468:
1469: According to the definition of atomicity in chapter 13 of \cite{Lyn96},
1470: atomicity means that each execution of one of the access procedures
1471: contains precisely one execution of the corresponding specifying action
1472: (fS), (dS), (iS), (aS). We introduced the private auxiliary variables
1473: \S cnt/ to count the number of times the specifying action is executed.
1474: Therefore, atomicity is expressed by the invariants:
1475: \begin{tab}
1476: %\\ ! G-FiCnt1!\\
1477: \S Cn1:/ \>$ \S pc/=14 \Implies \S cnt/_{\it fi}=1 $\\
1478: %\\ ! G-DeCnt1!\\
1479: \S Cn2:/ \>$ \S pc/\in\{25,26\} \Implies \S cnt/_{\it del}=1 $\\
1480: %\\ ! G-InCnt1!\\
1481: \S Cn3:/ \>$ \S pc/\in\{41,42\} \Implies \S cnt/_{\it ins}=1 $\\
1482: %\\ ! G-AsCnt1!\\
1483: \S Cn4:/ \>$ \S pc/=57 \Implies \S cnt/_{\it ass}=1 $
1484: \end{tab}
1485:
1486: We interpret absence of memory loss to mean that the number of
1487: allocated hash tables is bounded. More precisely, we prove that
1488: this number is bounded by $2P$. This is formalized in the invariant:
1489: \begin{tab} % NoLoss
1490: \S No1:/ \>$ \sharp \{k \mid k < \T H/_-\T index/\Land
1491: \T Heap/(k)\neq\bot\}\leq 2P$
1492: \end{tab}
1493:
1494: An important safety property is that no
1495: process accesses deallocated memory. Since most procedures perform
1496: memory accesses, by means of pointers that are local variables, the
1497: proof of this is based on a number of different invariants. Although,
1498: this is not explicit in the specification, it has been checked
1499: because the theorem prover PVS does not allow access to
1500: deallocated memory as this would violate type correctness conditions.
1501:
1502: \subsection{Intuitive proof}\label{intuproof}
1503:
1504: The eight correctness properties (invariants) mentioned above have
1505: been completely proved with the interactive proof checker of PVS.
1506: The use of PVS did not only take care of the delicate bookkeeping
1507: involved in the proof, it could also deal with many trivial cases
1508: automatically. At several occasions where PVS refused to let a proof
1509: be finished, we actually found a mistake and
1510: had to correct previous versions of this algorithm.
1511:
1512: In order to give some feeling for the proof, we describe some proofs.
1513: For the complete mechanical proof,
1514: we refer the reader to \cite{HesMv}. Note that, for simplicity, we
1515: assume that all non-specific private variables in the proposed
1516: assertions belong to the general process $p$, and general process $q$
1517: is an active process that tries to
1518: threaten some assertion ($p$ may equal $q$).\\
1519:
1520: \noindent \B Proof/ of invariant \S Co1/ (as claimed in
1521: \ref{safetymain}). According to Appendix B, the
1522: stability of \S Co1/ follows from the invariants \S Ot3/, \S fi1/,
1523: \S fi10/, which are given in Appendix A.
1524: Indeed, \S Ot3/ implies that no procedure returns to location 14.
1525: Therefore all return statements falsify the antecedent of \S Co1/ and
1526: thus preserve \S Co1/. Since $r_{\it fi}$ and $rS_{\it fi}$ are
1527: private variables to process $p$, \S Co1/ can only be violated by
1528: process $p$ itself (establishing $\S pc at 14/$) when $p$ executes 13
1529: with $r_{\it fi}=\B null/\Lor a_{\it fi}=\S ADR/(r_{\it fi})$. This
1530: condition is abbreviated as $\S Find/(r_{\it fi},a_{\it fi})$.
1531: Invariant \S fi10/ then implies that action 13 has the precondition
1532: $\S val/(r_{\it fi})=rS_{\it fi}$, so then it does not violate
1533: \S Co1/. In PVS, we used a slightly different definition of \S Find/,
1534: and we applied invariant \S fi1/ to exclude that $r_{\it fi}$ is
1535: \B done/ or \B del/, though invariant \S fi1/ is superfluous
1536: in this intuitive proof.\qed \\
1537:
1538: \noindent \B Proof/ of invariant \S Ot3/. Since the procedures
1539: \S getAccess/, \S releaseAccess/, \S refresh/, \S newTable/ are
1540: called only at specific locations in the algorithm, it is easy to
1541: list the potential return addresses. Since the variables \S return/
1542: are private to process $p$, they are not modified by other processes.
1543: Stability of \S Ot3/ follows from this.
1544: As we saw in the previous proof, \S Ot3/ is used to
1545: guarantee that no unexpected jumps occur.\qed \\
1546:
1547: \noindent \B Proof/ of invariant \S fi10/. According to Appendix B,
1548: we only need to use \S fi9/ and \S Ot3/. Let us use the abbreviation
1549: $k = \S key/(a_{\it fi},l_{\it fi},n_{\it fi})$. Since $r_{\it fi}$ and
1550: $rS_{\it fi}$ are both private variables, they can only be modified by
1551: process $p$ when $p$ is executing statement 7. We split this situation
1552: into two cases
1553: \begin{enumerate}
1554: \item with precondition $\S Find/(h_{\it fi}.\T table/[k],a_{\it fi})$\\
1555: After execution of statement 7, $r_{\it fi}$ becomes $h_{\it fi}.
1556: \T table/[k]$,
1557: and $rS_{\it fi}$ becomes $\T X/(a_{\it fi})$. By \S fi9/, we get
1558: $\S val/(r_{\it fi})=rS_{\it fi}$. Therefore the validity of \S fi10/
1559: is preserved.
1560: \item otherwise.\\
1561: After execution of statement 7, $r_{\it fi}$ becomes
1562: $h_{\it fi}.\T table/[k]$,
1563: which then falsifies the antecedent of \S fi10/. \qed \\
1564: \end{enumerate}
1565:
1566: \noindent \B Proof/ of invariant \S fi9/. According to Appendix B, we
1567: proved that \S fi9/ follows
1568: from \S Ax2/, \S fi1/, \S fi3/, \S fi4/, \S fi5/, \S fi8/,
1569: \S Ha4/, \S He4/, \S Cu1/, \S Cu9/, \S Cu10/, and \S Cu11/.
1570: We abbreviate $\S key/(a_{\it fi},l_{\it fi},n_{\it fi})$ as $k$.
1571: We deduce $h_{\it fi}=\T H/(\S index/)$ from \S fi4/,
1572: $\T H/(\S index/)$ is not
1573: $\bot$ from \S He4/, and $k$ is below $\T H/(\S index/).\T size/$ from
1574: \S Ax2/, \S fi4/ and \S fi3/. We split the proof into two cases:
1575:
1576: \begin{enumerate}
1577: \item $\S index/\neq\T currInd/$: By \S Ha4/, it follows that
1578: $\T H/(\S index/)\neq\T H/(\T currInd/)$. Hence from \S Cu1/, we obtain
1579: $h_{\it fi}.\T table/[k]=\B done/$, which falsifies the antecedent of
1580: \S fi9/.
1581: \item $\S index/=\T currInd/$:
1582: By premise $\S Find/(h_{\it fi}.\T table/[k],a_{\it fi})$, we know that
1583: $h_{\it fi}.\T table/[k]\neq\B done/$ because of \S fi1/. By \S Cu9/
1584: and \S Cu10/, we obtain
1585: $\S val/(h_{\it fi}.\T table/[k])=\S val/(\T Y/[k])$.
1586: Hence it follows that $\S Find/(\T Y/[k],a_{\it fi})$. Using \S fi8/,
1587: we obtain
1588: \begin{tab}
1589: \>$\forall m<n_{\it fi}:
1590: \neg \S Find/(\T Y/[\S key/(a_{\it fi},\S curSize/,m)],a_{\it fi})$
1591: \end{tab}
1592: We get $n_{\it fi}$ is below $\S curSize/$ because of \S fi5/.
1593: By \S Cu11/, we conclude
1594: \begin{tab}
1595: \>$\T X/(a_{\it fi})= \S val/(h_{\it fi}.\T table/[k])$
1596: \end{tab}
1597: \vspace{-5mm}\qed \\
1598: \end{enumerate}
1599:
1600: \subsection {The model in PVS} \label{pvs-model}
1601:
1602: Our proof architecture (for one property) can be described as a
1603: dynamically growing tree in which each node is associated with an
1604: assertion. We start from a tree containing only one node, the proof
1605: goal, which characterizes some property of the system. We expand
1606: the tree by adding some new children via proper analysis of an
1607: unproved node (top-down approach, which requires a good understanding
1608: of the system). The validity of that unproved node is then reduced to
1609: the validity of its children and the validity of
1610: some less or equally deep nodes.
1611:
1612: Normally, simple properties of the system are proved with appropriate
1613: precedence, and then used to help establish more complex ones. It is
1614: not a bad thing that some property that was taken for granted turns
1615: out to be not valid. Indeed, it may uncover a defect of the algorithm,
1616: but in any case it leads to new insights in it.
1617:
1618: We model the algorithm as a transition system \cite{ZA92},
1619: which is described in the language of PVS in the following way.
1620: As usual in PVS, states are represented by a record with a number
1621: of fields:
1622: {\small
1623: \begin{tab}
1624: \> State : TYPE = $[\#$ \\
1625: \> \% \=global variables\\
1626: \> \>...\\
1627: \> \>busy : [ range(2*P) $\rightarrow$ nat ],\\
1628: \> \>prot : [ range(2*P) $\rightarrow$ nat ],\\
1629: \> \>...\\
1630: \> \% private variables:\\
1631: \> \>index : [ range(P) $\rightarrow$ range(2*P) ],\\
1632: \> \>...\\
1633: \> \>pc : [ range(P) $\rightarrow$ nat ], \% private program counters\\
1634: \> \>...\\
1635: \> \% local variables of procedures, also private to each process:\\
1636: \> \% find \\
1637: \> \>a$_-$find : [ range(P) $\rightarrow$ Address ],\\
1638: \> \>r$_-$find : [ range(P) $\rightarrow$ EValue ],\\
1639: \> \>...\\
1640: \> \% getAccess \\
1641: \> \>return$_-$getAccess : [ range(P) $\rightarrow$ nat ],\\
1642: \> \>...\\
1643: \> \#]
1644: \end{tab}}
1645: \noindent where \S range/(\R P/) stands for the range
1646: of integers from 1 to P.
1647:
1648: Note that private variables are given with as argument a process
1649: identifier. Local variables are distinguished by adding their
1650: procedure's names as suffixes.
1651:
1652: An action is a binary relation on states: it relates the state
1653: prior to the action to the state following the action. The system
1654: performed by a particular process is then specified by defining the
1655: precondition of each action as a predicate on the state and also the
1656: effect of each action in terms of a state transition. For example,
1657: line 5 of the algorithm is described in PVS as follows:
1658: {\small
1659: \begin{tab}
1660: \>\% corresponding to statement find5: $h:=\T H/[\S index/]$; $ n:=0 $;\\
1661: \>find5(\=i,s1,s2) : bool = \\
1662: \>\>pc(s1)(i)=5 AND\\
1663: \>\>s2 = s1 WITH [ \=(pc)(i) := 6,\\
1664: \>\>\>(n$_-$find)(i) := 0,\\
1665: \>\>\>(h$_-$find)(i) := H(s1)(index(s1)(i)) ]
1666: \end{tab}}
1667: \noindent
1668: where $i$ is a process identifier, s1 is a pre-state, s2
1669: is a post-state.
1670:
1671: Since our algorithm is concurrent, the global transition relation is
1672: defined as the disjunction of all atomic actions.
1673: {\small
1674: \begin{tab}
1675: \>\% transition steps \\
1676: \>step(\=i,s1,s2) : bool = \\
1677: \>\> find5(i,s1,s2) or find6(i,s1,s2) or ... \\
1678: \>\> delete15(i,s1,s2) or delete16(i,s1,s2) or ...\\
1679: \>\>...
1680: \end{tab}}
1681: \noindent
1682: Stability for each invariant is proved by a PVS \S Theorem/ of the form:
1683: {\small
1684: \begin{tab}
1685: \>\% Theorem about the stability of invariant fi10 \\
1686: \>IV$_-$fi10: THEOREM \\
1687: \>\> forall (u,v : state, q : range(P) ) : \\
1688: \>\>\> step(q,u,v) AND fi10(u) AND fi9(u) AND ot3(u) \\
1689: \>\>\> =$>$ fi10(v)
1690: \end{tab}}
1691: \noindent
1692: To ensure that all proposed invariants are stable, there is a
1693: global invariant \T INV/, which is the conjunction of all proposed invariants.
1694: {\small
1695: \begin{tab}
1696: \>\% global invariant \\
1697: \>INV(s:state) : bool = \\
1698: \>\> He3(s) and He4(s) and Cu1(s) and ... \\
1699: \>\>...
1700: \end{tab}
1701: \begin{tab}
1702: \>\% Theorem about the stability of the global invariant INV \\
1703: \>IV$_-$INV: THEOREM \\
1704: \>\> forall (u,v : state, q : range(P) ) : \\
1705: \>\>\> step(q,u,v) AND INV(u) =$>$ INV(v)
1706: \end{tab}}
1707: \noindent
1708: We define \T Init/ as all possible initial states, for which all
1709: invariants must be valid.
1710: {\small
1711: \begin{tab}
1712: \>\% initial state \\
1713: \>Init: \{ s : state $\mid$ \\
1714: \>\>\>(forall (p: range(P)):\\
1715: \>\>\>\> pc(s)(p)=0 and ...\\
1716: \>\>\>\> ...) and\\
1717: \>\>\>(forall (a: Address):\\
1718: \>\>\>\> X(s)(a)=null) and \\
1719: \>\>\>...\\
1720: \>\>\> \}
1721: \end{tab}
1722: \begin{tab}
1723: \>\% The initial condition can be satisfied by the global invariant
1724: INV \\
1725: \>IV$_-$Init: THEOREM \\
1726: \>\> INV(Init)
1727: \end{tab}}
1728: \noindent
1729: The PVS code contains ll
1730: preconditions to imply well-definedness:
1731: e.g. in \S find7/, the hash table must be non-NIL and $\ell$
1732: must be its size.
1733: {\small
1734: \begin{tab}
1735: \>\% corresponding to statement find7\\
1736: \>find7(\=i,s1,s2) : bool = \\
1737: \>\> i?(Heap(s1)(h$_-$find(s1)(i))) and\\
1738: \>\> l$_-$find(s1)(i)=size(i$_-$(Heap(s1)(h$_-$find(s1)(i)))) and \\
1739: \>\> pc(s1)(i)=7 and\\
1740: \>\> ...
1741: \end{tab}}
1742:
1743: All preconditions are allowed, since we can prove lock-freedom in
1744: the following form. In every state $s1$ that satisfies the global
1745: invariant, every process $q$ can perform a step, i.e., there is a
1746: state $s2$ with $(s1,s2)\in\S step/$ and
1747: $\S pc/(s1,q)\ne\S pc/(s2,q)$. This is expressed in PVS by
1748: {\small
1749: \begin{tab}
1750: \>\% theorem for lock-freedom\\
1751: \>IV$_-$prog: THEOREM \\
1752: \>\> forall (u: state, q: range(P) ) : \\
1753: \>\>\> INV(u) =$>$ exists (v: state): pc(u)(q) /= pc(v)(q) and step(q,u,v)
1754: \end{tab}}
1755:
1756: \section{Correctness (Progress)} \label{progress}
1757:
1758: In this section, we prove that our algorithm is lock-free, and that
1759: it is wait-free for several subtasks.
1760: Recall that an algorithm is called {\it lock-free} if always at least
1761: some process will finish its task in a
1762: finite number of steps, regardless of delays or failures by other
1763: processes. This means that no process can block the applications
1764: of further operations to the data structure, although any particular
1765: operation need not terminate since a slow process can be passed
1766: infinitely often by faster processes.
1767: We say that an operation is {\it wait-free} if any process involved
1768: in that operation is guaranteed to complete it in a finite number of
1769: its own steps, regardless of the (in)activity of other processes.
1770:
1771: \subsection {The easy part of progress }
1772:
1773: It is clear that \S releaseAccess/ is wait-free. It follows that
1774: the wait-freedom of \S migrate/ depends on wait-freedom of
1775: \S moveContents/. The loop of \S moveContents/ is clearly bounded.
1776: So, wait-freedom of \S moveContents/ depends on wait-freedom of
1777: \S moveElement/. It has been proved that $n$
1778: is bounded by $m$ in \S moveElement/ (see invariants \S mE3/ and
1779: \S mE8/). Since, moreover, $\S to/.\T table/[k]\neq \B null/$ is
1780: stable, the loop of \S moveElement/ is also bounded. This concludes
1781: the sketch that \S migrate/ is wait-free.
1782:
1783: \subsection {Progress of newTable}
1784:
1785: The main part of procedure \S newTable/ is wait-free. This can be
1786: shown informally, as follows.
1787: Since we can prove the condition $\T next/(\S index/)\neq 0$ is
1788: stable while process $p$ stays in the region $[77,84]$, once the
1789: condition $\T next/(\S index/)\neq 0$
1790: holds, process $p$ will exit \S newTable/ in a few rounds.
1791:
1792: Otherwise, we may assume that $p$ has precondition
1793: $\T next/(\S index/)= 0$ before executing line 78. By the invariant
1794: \begin{tab}
1795: %\\ ! G-next-index1!\\
1796: \S Ne5:/ \>$ pc\in [1,58]\LOR pc\geq 62 \Land pc\neq 65 \Land
1797: \T next/(\S index/)=0$\\
1798: \> $\implies\quad \S index/=\T currInd/$
1799: \end{tab}
1800: we get that $\S index/ = \T currInd/$ holds and
1801: $\T next/(\T currInd/)= 0$ from
1802: the precondition. We define two sets of integers:
1803: \begin{tab} %G-prot-set-a
1804: \>\+ $ \S prSet1/(i) \IS
1805: \{r\mid \S index/.r=i \Land pc.r \notin \{0,59,60\}\}$\\
1806:
1807: %G-prot-set-b
1808: $\S prSet2/(i) \IS
1809: \{r\mid \S index/.r=i \Land pc.r \in \{104,105\} $\+\+\+\+\+ \\
1810: $\lor~ i_{\it rA}.r=i \Land \S index/.r \neq i \Land pc.r
1811: \in [67,72] $\\
1812: $\lor~ i_{\it nT}.r=i \Land pc.r \in [81,84]$\\
1813: $\lor~ i_{\it mig}.r=i \Land pc.r \geq 97\;\}$
1814: \end{tab}
1815: and consider the sum
1816: $\sum_{i=1}^{2P}(\sharp (prSet1(i)) ~+~ \sharp (prSet2(i)))$.
1817: While process $p$ is at line $78$, the sum cannot exceed $2P-1$
1818: because there are only $P$ processes around and process $p$
1819: contributes only once to the sum. It then follows from the pigeon
1820: hole principle that there exists $j\in [1,2P]$ such that
1821: $\sharp (prSet1(j)) ~+~ \sharp (prSet2(j))=0$
1822: and $j\neq \S index/.p$. By the invariant
1823: \begin{tab}
1824: %\\ ! G-prot!\\
1825: \S pr1:/\> $ \T prot/[j] = \sharp (\S prSet1/(j)) +
1826: \sharp (\S prSet2/(j)) +
1827: \sharp (\T currInd/=j)$\\
1828: \>\>\>\> $ + \sharp (\T next/(\T currInd/)=j)$
1829: \end{tab}
1830: we can get that $\T prot/[j]=0$ because of
1831: $j\neq \S index/.p = \T currInd/$.
1832:
1833: While \T currInd/ is constant, no process can modify $\T prot/[j]$ for
1834: $j\neq \T currInd/$ infinitely often. Therefore, if process $p$ acts
1835: infinitely often and chooses its value $i$ in 78 by round robin,
1836: process $p$ exits the loop of \S newTable/ eventually. This shows
1837: that the main part of \S newTable/ is wait-free.
1838:
1839: \subsection{The failure of wait-freedom}
1840: Procedure \S getAccess/ is not wait-free. When the active clients
1841: keep changing the current index faster than the new client can
1842: observe it, the accessing client is doomed to starvation. In that case,
1843: however, the other processes repeatedly succeed. It follows that
1844: \S getAccess/, \S refresh/, and \S newTable/ are lock-free.
1845:
1846: It may be possible to make a queue for the accessing clients which
1847: is emptied by a process in \S newTable/. The accessing clients
1848: must however also be able to enter autonomously. This would at
1849: least add another layer of complications. We therefore prefer
1850: to treat this failure of wait-freedom as a performance issue that
1851: can be dealt with in practice by tuning the sizes of the hash tables.
1852:
1853: According to the invariants \S fi5/, \S de8/, \S in8/ and \S as6/,
1854: the primary procedures \S find/, \S delete/, \S insert/,
1855: \S assign/ are loops bounded by $n \leq h.\T size/$, and $n$ is only
1856: reset to 0 during migration. If $n$ is not reset to 0, it is
1857: incremented or stays constant. Indeed, the atomic \B if/ statements
1858: in 18b, 35b, and 50b have no \B else/ parts. In \S delete/ and
1859: \S assign/, it is therefore possible that $n$ stays constant without
1860: termination of the loop. Since
1861: \S assign/ can modify non-\B null/ elements of the table, it follows
1862: that \S delete/ and \S assign/ are not wait-free.
1863: This unbounded fruitless activity is possible only when \S assign/
1864: actions of other processes repeatedly succeed. It follows that the
1865: primary procedures are lock-free. This concludes the
1866: argument that the system is lock-free.
1867:
1868: \section {Conclusions} \label{conclusions}
1869:
1870: Lock-free shared data objects are inherently
1871: resilient to halting failures and permit maximum parallelism. We
1872: have presented a new practical, lock-free algorithm for
1873: concurrently accessible hash tables, which promises more robust
1874: performance and reliability than a conventional lock-based
1875: implementation. Moreover, the new algorithm is dynamic in the sense
1876: that it allows the hash table to grow and shrink as needed.
1877:
1878: The algorithm scales up linearly with the number of
1879: processes, provided the function {\it key} and the selection
1880: of $i$ in line 111 are defined well. This is confirmed by some
1881: experiments where random values were stored, retrieved
1882: and deleted from the hash table. These experiments indicated
1883: that $10^6$ insertions, deletions and finds per second and per
1884: processor are possible on an SGI powerchallenge with 250Mhz R12000
1885: processors. This figure should only be taken as a rough indicator,
1886: since the performance of parallel processing is very much influenced
1887: by the machine architecture, the relative sizes of data structures
1888: compared to sizes of caches, and even the scheduling of processes
1889: on processors.
1890:
1891: The correctness proof for our algorithm is noteworthy because of the
1892: extreme effort it took to finish it. Formal deduction by
1893: human-guided theorem proving can, in principle, verify any correct
1894: design, but doing so may require unreasonable amounts of effort,
1895: time, or skill. Though PVS provided great help for managing and
1896: reusing the proofs, we have to admit that the verification for our
1897: algorithm was very complicated due to the complexity of our
1898: algorithm. The total verification effort can roughly be estimated
1899: to consist of two man year excluding the effort in determining the
1900: algorithm and writing the documentation. The whole proof contains
1901: around 200 invariants. It takes an 1Ghz Pentium IV computer around
1902: two days to re-run an individual proof for one of the biggest
1903: invariants. Without suitable tool support like PVS, we even doubt
1904: if it would be possible to complete a
1905: reliable proof of such size and complexity.
1906:
1907: It may well be possible to simplify the proof and reduce the number
1908: of invariants slightly, but we did not work on this. The complete
1909: version of the PVS specifications and the whole proof scripts can
1910: be found at \cite{HesMv}. Note that we simplified some definitions
1911: in the paper for the sake of presentation.\\
1912:
1913: \appendix
1914: \section{Invariants} \label{Inv}
1915: We present here all invariants whose validity has been verified
1916: by the theorem prover PVS.
1917:
1918: \newenvironment{tab1}{\begin{tabbing}
1919: MMMa\=aaa\=aaa\=aaa\=aaa\=aaa\=aaa\= \kill}{\end{tabbing}}
1920: \medbreak Conventions. We abbreviate
1921: \begin {tab1}
1922: \>$\S Find/(\T r/,\T a/)\triangleq ~\T r/=\B null/\Lor \T a/=\S ADR/(\T r/)$ \\
1923: \>$\S LeastFind/(a,n)\triangleq ~$\=$~(\forall m<n:\neg \S Find/(\T Y/[\S key/(a,\S curSize/,m)],a))$\\
1924: \>\>$\land~\S Find/(\T Y/[\S key/(a,\S curSize/,n)],a))$\\
1925: \> $\S LeastFind/(h,a,n)\triangleq ~$\=$~(\forall m<n:\neg \S Find/(h.\T table/[\S key/(a,h.\T size/,m)],a))$\\
1926: \>\>$\land~\S Find/(h.\T table/[\S key/(a,h.\T size/,n)],a))$
1927: \end {tab1}
1928:
1929: \medbreak Axioms on functions \S key/ and \S ADR/
1930: \begin{tab1}
1931: %\\ ! ADRjective!\\
1932: \S Ax1:/ \>$ v=\B null/\EQ \S ADR/(v)=\B 0/$ \\
1933: %\\ ! KEYinRange!\\
1934: \S Ax2:/ \>$ 0\leq \S key/(a,l,k) < l$\\
1935: %\\ ! KEYdifferent!\\
1936: \S Ax3:/ \>$ 0\leq k < m < l ~\implies \quad \S key/(a,l,k)\neq \S key/(a,l,m)$
1937: \end{tab1}
1938:
1939: \medbreak Main correctness properties
1940: \begin{tab1}
1941: %\\ ! Correct1!\\
1942: \S Co1:/ \>$ pc=14 ~\implies \quad \S val/(r_{\it fi})=rS_{\it fi}$ \\
1943: %\\ ! Correct2!\\
1944: \S Co2:/ \>$ pc\in \{25,26\} ~\implies \quad suc_{\it del}=sucS_{\it del}$ \\
1945: %\\ ! Correct3!\\
1946: \S Co3:/ \>$ pc\in \{41,42\} ~\implies \quad suc_{\it ins}=sucS_{\it ins}$\\
1947: %\\ ! G-FiCnt1!\\
1948: \S Cn1:/ \>$ pc=14 ~\implies \quad cnt_{\it fi}=1 $\\
1949: %\\ ! G-DeCnt1!\\
1950: \S Cn2:/ \>$ pc\in\{25,26\} ~\implies \quad cnt_{\it del}=1 $\\
1951: %\\ ! G-InCnt1!\\
1952: \S Cn3:/ \>$ pc\in\{41,42\} ~\implies \quad cnt_{\it ins}=1 $\\
1953: %\\ ! G-AsCnt1!\\
1954: \S Cn4:/ \>$ pc=57 ~\implies \quad cnt_{\it ass}=1 $
1955: \end{tab1}
1956: The absence of memory loss is shown by
1957: \begin{tab1}
1958: %\\ ! NoLoss!\\
1959: \S No1:/ \>$ \sharp (nbSet1) \leq 2*P$ \\
1960: %\\ ! NoLoss1!\\
1961: \S No2:/ \>$ \sharp (nbSet1)=\sharp (nbSet2)$
1962: \end{tab1}
1963: where $nbSet1$ and $nbSet2$ are sets of integers, characterized by
1964: \begin{tab1}
1965: %\\ ! H-nonbot!\\
1966: $\S nbSet1/ \IS \{k \mid k < \T H/_-\T index/\Land \T Heap/(k)\neq\bot\}$\\
1967:
1968: %\\ ! H-nonbot1!\\
1969: $\S nbSet2/ \IS
1970: \{i\mid \T H/(i)\neq 0 \lor (\exists r:pc.r=71 \land i_{\it rA}.r=i)\}$
1971: \end{tab1}
1972:
1973:
1974: \medbreak Further, we have the following definitions of sets of integers:
1975:
1976: \begin{tab1}
1977: %\\ ! G-ghostset1!\\
1978: $\S deSet1/ \IS \{k\mid k < \S curSize/\Land \T Y/[k]=\B del/\}$\\
1979:
1980: %\\ ! G-delset1!\\
1981: $\S deSet2/ \IS \{r\mid \S index/.r=\T currInd/ \Land pc.r=25 \land
1982: suc_{\it del}.r\}$\\
1983:
1984: %\\ ! G-delset!\\
1985: $\S deSet3/\IS \{k\mid k < \T H/(\T next/(\T currInd/)).\T size/ $\\
1986: \> $\Land \T H/(\T next/(\T currInd/)).\T table/[k]=\B del/\}$ \\
1987:
1988: %\\ ! G-occset1!\\
1989: $\S ocSet1/\IS \{r\mid \S index/.r\neq \T currInd/$\\
1990: \>\>$\lor\; pc.r\in [30,41] \Lor pc.r\in [46,57]$\\
1991: \>\>$\lor\; pc.r \in [59,65]\Land return_{\it gA}.r\geq 30$ \\
1992: \>\>$\lor\; $\=$pc.r \in [67,72]\land\; (return_{\it rA}.r=59\Land return_{\it gA}.r\geq 30$\\
1993: \>\>\>\>$\lor\; return_{\it rA}.r=90\Land return_{\it ref}.r\geq 30)$ \\
1994: \>\>$\lor\; (pc.r=90\Lor pc.r\in [104,105])\Land return_{\it ref}.r\geq 30\}$ \\
1995:
1996: %\\ ! G-occset2!\\
1997: $\S ocSet2/ \IS \{r\mid pc.r \geq 125 \Land b_{\it mE}.r \Land
1998: to.r=\T H/(\T currInd/)\} $ \\
1999:
2000: %\\ ! G-occset3!\\
2001: $\S ocSet3/ \IS
2002: \{r\mid \S index/.r=\T currInd/ \Land pc.r=41 \Land suc_{\it ins}.r$\\
2003: \>\>$\Lor \S index/.r=\T currInd/ \Land pc.r=57\Land r_{\it ass}.r=\B null/\}$\\
2004:
2005: %\\ ! G-set1!\\
2006: $\S ocSet4/\IS \{k\mid
2007: k < \S curSize/ \Land \S val/(\T Y/[k])\neq\B null/\}$\\
2008:
2009: %\\ ! G-set2!\\
2010: $\S ocSet5/\IS
2011: \{k\mid k <\T H/(\T next/(\T currInd/)).\T size/ $\\
2012: \>\>$\Land \S val/(\T H/(\T next/(\T currInd/)).\T table/[k])\neq\B null/\}$\\
2013:
2014: %\\ ! G-nextset!\\
2015: $\S ocSet6/\IS
2016: \{k\mid k < \T H/(\T next/(\T currInd/)).\T size/ $\\
2017: \>\>$\Land \T H/(\T next/(\T currInd/)).\T table/[k]\neq\B null/\}$\\
2018:
2019: %\\ ! G-nextset1!\\
2020: $\S ocSet7/\IS \{r\mid pc.r\geq 125\Land
2021: b_{\it mE}.r\Land to.r=\T H/(\T next/(\T currInd/))\}$ \\
2022:
2023: %\\ ! G-prot-set!\\
2024: $ \S prSet1/(i) \IS
2025: \{r\mid \S index/.r=i \Land pc.r \notin \{0,59,60\}\}$\\
2026:
2027: %\\ ! G-prot-set!\\
2028: $\S prSet2/(i) \IS
2029: \{r\mid \S index/.r=i \Land pc.r \in \{104,105\} $\\
2030: \>\>$\lor~ i_{\it rA}.r=i \Land \S index/.r \neq i \Land pc.r
2031: \in [67,72] $\\
2032: \>\>$\lor~ i_{\it nT}.r=i \Land pc.r \in [81,84]$\\
2033: \>\>$\lor~ i_{\it mig}.r=i \Land pc.r \geq 97\}$\\
2034:
2035: %\\ ! G-prot-set1!\\
2036: $\S prSet3/(i)\IS
2037: \{r\mid \S index/.r=i \Land pc.r \in [61,65]\cup [104,105] $\\
2038: \>\>$\lor~ i_{\it rA}.r=i \Land pc.r=72 $\\
2039: \>\>$\lor~ i_{\it nT}.r=i \Land pc.r \in [81,82]$\\
2040: \>\>$\lor~ i_{\it mig}.r=i \Land pc.r \in [97,98]\}$\\
2041:
2042: %\\ ! G-prot-set2!\\
2043: $\S prSet4/(i) \IS
2044: \{r\mid \S index/.r=i \Land pc.r \in [61,65] $\\
2045: \>\>$\lor~ i_{\it mig}.r=i \Land pc.r \in [97,98]\}$ \\
2046:
2047: %\\ ! G-busy-set!\\
2048: $\S buSet1/(i) \IS
2049: \{r\mid \S index/.r=i$\\
2050: \>\>$\land~ $\=$(pc.r \in [1,58]\cup (62,68]\Land pc.r\neq 65$\\
2051: \>\>\>$\lor~ pc.r\in [69,72] \Land return_{\it rA}.r>59$\\
2052: \>\>\>$\lor~ pc.r>72)\}$ \\
2053:
2054: %\\ ! G-busy-set!\\
2055: $\S buSet2/(i)\IS
2056: \{r\mid \S index/.r=i \Land pc.r=104$\\
2057: \>\>$\lor~ i_{\it rA}.r=i \Land \S index/.r \neq i \Land pc.r \in [67,68] $\\
2058: \>\>$\lor~ i_{\it nT}.r=i \Land pc.r \in [82,84]$\\
2059: \>\>$\lor~ i_{\it mig}.r=i \Land pc.r \geq 100\}$
2060: \end{tab1}
2061:
2062:
2063: \medbreak We have the following invariants concerning the \T Heap/
2064: \begin{tab1}
2065: %\\ ! G-H5!\\
2066: \S He1:/ \>$ \T Heap/(0)=\bot$ \\
2067:
2068: %\\ ! G-H2,G-H4!\\
2069: \S He2:/ \>$ \T H/(i)\neq 0\equiv \T Heap/(\T H/(i))\neq \bot$\\
2070:
2071: %\\ ! G-k0-a!\\
2072: \S He3:/\>$ \T Heap/(\T H/(\T currInd/))\neq \bot$ \\
2073:
2074: %\\ ! G-k0-b!\\
2075: \S He4:/\>$ pc \in [1,58] \Lor pc>65 \Land \neg(pc \in [67,72]\Land i_{\it rA}=\S index/)$\\
2076: \>$\implies \quad \T Heap/(\T H/(\S index/))\neq \bot$ \\
2077:
2078: %\\ ! G-k2!\\
2079: \S He5:/\>$ \T Heap/(\T H/(i))\neq \bot ~\implies \quad\ \T H/(i).\T size/\geq P$\\
2080:
2081: %\\ ! G-next-currInd4!\\
2082: \S He6:/\>$ \T next/(\T currInd/)\neq 0~\implies \quad
2083: \T Heap/(\T H/(\T next/(\T currInd/)))\neq\bot$
2084: \end{tab1}
2085:
2086: \medbreak Invariants concerning hash table pointers
2087: \begin{tab1}
2088: %\\ ! G-H-index1!\\
2089: \S Ha1:/ \>$ \T H/_-\T index/>0$ \\
2090:
2091: %\\ ! G-H-index!\\
2092: \S Ha2:/ \>$ \T H/(i)<\T H/_-\T index/$ \\
2093:
2094: %\\ ! G-H1!\\
2095: \S Ha3:/ \>$ i\neq j\Land \T Heap/(\T H/(i))\neq \bot ~\implies \quad \T H/(i)\neq\T H/(j)$\\
2096:
2097: %\\ ! G-index!\\
2098: \S Ha4:/ \>$ \S index/\neq \T currInd/~\implies \quad\ \T H/(\S index/)\neq \T H/(\T currInd/)$ \\
2099: %\>;this can be eliminated by (k0-a) and (H1)
2100: \end{tab1}
2101:
2102: Invariants about counters for calling the specification.
2103:
2104: \begin{tab1}
2105: %\\ ! G-FiCnt3!\\
2106: \S Cn5:/ \>$ pc\in [6,7]~\implies \quad cnt$\=$_{\it fi}=0 $\\
2107: %\\ ! G-FiCnt2!\\
2108: \S Cn6:/ \>$ pc\in [8,13]$\\
2109: \>$\lor~ pc\in [59,65] \land return_{\it gA}=10$\\
2110: \>$\lor~ pc\in [67,72] \land ($\=$return_{\it rA}=59 \land return_{\it gA}=10$\\
2111: \>\>$\lor~ return_{\it rA}=90 \land return_{\it ref}=10$\\
2112: \>$\lor~ pc \geq 90 \Land return_{\it ref}=10$ \\
2113: \>$\implies \quad cnt$\=$_{\it fi}=\sharp (r_{\it fi}=\B null/\lor a_{\it fi}=\S ADR/(r_{\it fi}))$ \\
2114:
2115: %\\ ! G-DeCnt2!\\
2116: \S Cn7:/ \>$ pc\in [16,21]\Land pc\neq 18 $\\
2117: \>$\lor~ pc\in [59,65] \land return_{\it gA}=20$\\
2118: \>$\lor~ pc\in [67,72] \land ($\=$return_{\it rA}=59 \land return_{\it gA}=20$\\
2119: \>\>$\lor~ return_{\it rA}=90 \land return_{\it ref}=20$\\
2120: \>$\lor~ pc \geq 90 \Land return_{\it ref}=20$ \\
2121: \>$\implies \quad cnt_{\it del}= 0$\\
2122:
2123: %\\ ! G-DeCnt3!\\
2124: \S Cn8:/ \>$ pc=18 ~\implies \quad cnt_{\it del}=\sharp (r_{\it del}=\B null/)$\\
2125:
2126: %\\ ! G-InCnt3!\\
2127: \S Cn9:/ \>$ pc\in [28,33]$\\
2128: \>$\lor~ pc\in [59,65] \land return_{\it gA}=30$\\
2129: \>$\lor~ pc\in [67,72] \land ($\=$return_{\it rA}=59 \land return_{\it gA}=30$\\
2130: \>\>$\lor~ return_{\it rA}=77 \land return_{\it nT}=30$\\
2131: \>\>$\lor~ return_{\it rA}=90 \land return_{\it ref}=30$\\
2132: \>$\lor~ pc\in [77,84] \land return_{\it nT}=30 $\\
2133: \>$\lor~ pc \geq 90 \Land return_{\it ref}=30$ \\
2134: \>$\implies \quad cnt_{\it ins}= 0$ \\
2135:
2136: %\\ ! G-InCnt2!\\
2137: \S Cn10:/ \>$ pc\in [35,37]$\\
2138: \>$\lor~ pc\in [59,65] \land return_{\it gA}=36$\\
2139: \>$\lor~ pc\in [67,72] \land ($\=$return_{\it rA}=59 \land return_{\it gA}=36$\\
2140: \>\>$\lor~ return_{\it rA}=90 \land return_{\it ref}=36$\\
2141: \>$\lor~ pc \geq 90 \Land return_{\it ref}=36$ \\
2142: \>$\implies \quad cnt_{\it ins}= \sharp (a_{\it ins}=\S ADR/(r_{\it ins})\lor suc_{\it ins})$\\
2143:
2144: %\\ ! G-AsCnt2!\\
2145: \S Cn11:/ \>$ pc\in [44,52]$\\
2146: \>$\lor~ pc\in [59,65] \land return_{\it gA}\in \{46,51\}$\\
2147: \>$\lor~ pc\in [67,72] \land ($\=$return_{\it rA}=59 \land return_{\it gA} \in \{46,51\}$\\
2148: \>\>$\lor~ return_{\it rA}=77 \land return_{\it nT}=46$\\
2149: \>\>$\lor~ return_{\it rA}=90 \land return_{\it ref} \in \{46,51\}$\\
2150: \>$\lor~ pc\in [77,84] \land return_{\it nT}=46 $\\
2151: \>$\lor~ pc \geq 90 \Land return_{\it ref}\in \{46,51\}$ \\
2152: \>$\implies \quad cnt_{\it ass}sign= 0$
2153: \end{tab1}
2154:
2155: \medbreak Invariants about old hash tables, current hash table and the auxiliary hash table \T Y/.
2156: Here, we universally quantify over all non-negative integers $n< \S curSize/$.
2157: \begin{tab1}
2158: %\\ ! G-k1!\\
2159: \S Cu1:/ \>$ \T H/(\S index/)\neq \T H/(\T currInd/)\Land k < \T H/(\S index/).\T size/$\\
2160: \>$\land~ (pc\in [1,58]\Lor pc>65 \Land
2161: \neg( pc\in[67,72]\Land i_{\it rA}=\S index/)$\\
2162: \>$\implies\quad \T H/(\S index/).\T table/[k]=\B done/$ \\
2163:
2164: %\\ ! G-ghostocc1!\\
2165: \S Cu2:/ \>$\sharp(\{k\mid k < \S curSize/\Land \T Y/[k]\neq\B null/\})<\S curSize/$ \\
2166:
2167: %\\ ! G-bound1!\\
2168: \S Cu3:/ \>$ \T H/(\T currInd/).\T bound/+2*P<\S curSize/$\\
2169:
2170: %\\ ! G-ghostdel1!\\
2171: \S Cu4:/ \>$ \T H/(\T currInd/).\T dels/+\sharp(deSet2)=\sharp(deSet1)$\\
2172:
2173: %\\ ! G-ghostocc,G-ghostset!\\
2174: \S Cu5:/ \>\S Cu5/ has been eliminated. The numbering has been kept, so as not to\\
2175: \> endanger the consistency with Appendix B and the PVS script.\\
2176:
2177: %\\ ! G-ghostocc2!\\
2178: \S Cu6:/ \>$ \T H/(\T currInd/).\T occ/+\sharp (ocSet1)+\sharp (ocSet2)\leq\T H/(\T currInd/).\T bound/+2*P$\\
2179:
2180: %\\ ! G-ghostocc3!\\
2181: \S Cu7:/\>$\sharp(\{k\mid k < \S curSize/\Land\T Y/[k]\neq\B null/\}$ \\
2182: \> $ = \T H/(\T currInd/).\T occ/+\sharp (ocSet2) + \sharp (ocSet3)$\\
2183:
2184: %\\ ! G-next-currInd3!\\
2185: \S Cu8:/ \>$\T next/(\T currInd/) = 0~\implies \quad
2186: \neg\,\S oldp/(\T H/(\T currInd/).\T table/[n])$\\
2187:
2188: %\\ ! G-ghost1-a!\\
2189: \S Cu9:/ \>$\neg (\S oldp/(\T H/(\T currInd/).\T table/[n]))~\implies \quad
2190: \T H/(\T currInd/).\T table/[n]=\T Y/[n] $\\
2191:
2192: %\\ ! G-ghost1-b!\\
2193: \S Cu10:/ \>$\S oldp/(\T H/(\T currInd/).\T table/[n]) \Land \S val/(\T H/(\T currInd/).\T table/[n])\neq \B null/$\\
2194: \>$\implies\ \S val/(\T H/(\T currInd/).\T table/[n])=\S val/(\T Y/[n])$ \\
2195:
2196: %\\ ! G-ghost2-a!\\
2197: \S Cu11:/ \>$\S LeastFind/(a,n)~\implies \quad \T X/(a)=\S val/(\T Y/[\S key/(a,\S curSize/,n)])$\\
2198:
2199: %\\ ! G-ghost2-b!\\
2200: \S Cu12:/ \>$\T X/(a)=\S val/(\T Y/[\S key/(a,\S curSize/,n)])
2201: \neq \B null/~\implies \quad \S LeastFind/(a,n)$ \\
2202:
2203: %\\ ! G-ghost3-a!\\
2204: \S Cu13:/ \>$\T X/(a)=\S val/(\T Y/[\S key/(a,\S curSize/,n)])\neq \B null/
2205: \Land n \ne m < \S curSize/$\\
2206: \>$\implies \quad \S ADR/(\T Y/[\S key/(a,\S curSize/,m)])\neq a $ \\
2207:
2208: %\\ ! G-ghost3-b!\\
2209: \S Cu14:/ \>$\T X/(a)=\B null/\Land \S val/(\T Y/[\S key/(a,\S curSize/,n)])\neq \B null/$\\
2210: \>$\implies \quad \S ADR/(\T Y/[\S key/(a,\S curSize/,n)])\neq a$ \\
2211:
2212: %\\ ! G-ghost4!\\
2213: \S Cu15:/ \>$\T X/(a)\neq\B null/$\\
2214: \>$\implies\ \exists m < \S curSize/:\T X/(a)=\S val/(\T Y/[\S key/(a,\S curSize/,m)])$ \\
2215:
2216: %\\ ! G-ghostbij!\\
2217: \S Cu16:/ \>$\exists (f:[$\=$\{m:0\leq m<\S curSize/)\land \S val/(\T Y/[m])\neq \B null/\}\rightarrow $\\
2218: \>\>$\{v:v\neq\B null/\land (\exists k<\S curSize/:v=\S val/(\T Y/[k]))\}]):$\\
2219: \>$f~ \T is bijective/$
2220: \end{tab1}
2221:
2222:
2223: \medbreak Invariants about \T next/ and $\T next/(\T currInd/)$:
2224:
2225: \begin{tab1}
2226: %\\ ! G-next-currInd!\\
2227: \S Ne1:/ \>$ \T currInd/\neq\T next/(\T currInd/)$\\
2228:
2229: %\\ ! G-next-currInd1!\\
2230: \S Ne2:/ \>$ \T next/(\T currInd/)\neq 0~\implies \quad\T next/(\T next/(\T currInd/))=0$\\
2231:
2232: %\\ ! G-next-currInd2!\\
2233: \S Ne3:/ \>$ pc\in [1,59]\Lor pc\geq 62 \Land pc\neq 65~\implies \quad \S index/\neq\T next/(\T currInd/)$\\
2234:
2235: %\\ ! G-next-index!\\
2236: \S Ne4:/ \>$ pc\in [1,58]\Lor pc\geq 62 \Land pc\neq 65~\implies \quad \S index/\neq\T next/(\S index/)$\\
2237:
2238: %\\ ! G-next-index1!\\
2239: \S Ne5:/ \>$ pc\in [1,58]\Lor pc\geq 62 \Land pc\neq 65 \Land \T next/(\S index/)=0$\\
2240: \> $ \implies\quad \S index/=\T currInd/$\\
2241:
2242: %\\ ! G-ghostocc4!\\
2243: \S Ne6:/ \>$ \T next/(\T currInd/)\neq 0$\\
2244: \>$\implies \quad $\=$ \sharp (\S ocSet6/)\leq \sharp(\{k\mid k < \S curSize/\Land \T Y/[k]\neq\B null/\}-\T H/(\T currInd/).\T dels/$\\
2245: \>\>$-\sharp (deSet2)$\\
2246:
2247: %\\ ! G-nextbound1!\\
2248: \S Ne7:/ \>$ \T next/(\T currInd/)\neq 0$\\
2249: \>$\implies \quad $\=$\T H/(\T currInd/).\T bound/-\T H/(\T currInd/).\T dels/+2*P$\\
2250: \>\>$\leq\T H/(\T next/(\T currInd/)).\T bound/$\\
2251:
2252: %\\ ! G-nextbound2!\\
2253: \S Ne8:/ \>$ \T next/(\T currInd/)\neq 0$\\
2254: \>$\implies \quad \T H/(\T next/(\T currInd/)).\T bound/+
2255: 2*P<\T H/(\T next/(\T currInd/)).\T size/$\\
2256:
2257: %\\ ! G-nextdel!\\
2258: \S Ne9:/ \>$ \T next/(\T currInd/)\neq 0 ~\implies \quad
2259: \T H/(\T next/(\T currInd/)).\T dels/=\sharp (\S deSet3/)$\\
2260:
2261: %\\ ! G-Ne9a!\\
2262: \S Ne9a:/ \>$ \T next/(\T currInd/)\neq 0 ~\implies \quad
2263: \T H/(\T next/(\T currInd/)).\T dels/=0$ \\
2264:
2265: %\\ ! G-migrate9!\\
2266: \S Ne10:/ \>$ \T next/(\T currInd/)\neq 0 \Land k < h.\T size/~\implies \quad h.\T table/[k]\notin \{\B del/,\B done/\} $,\\
2267: \>where $h=\T H/(\T next/(\T currInd/))$\\
2268:
2269: %\\ ! G-migrate4-1!\\
2270: \S Ne11:/ \>$\T next/(\T currInd/)\neq 0\Land
2271: k < \T H/(\T next/(\T currInd/)).\T size/ $\\
2272: \> $\implies\quad \neg\S oldp/(\T H/(\T next/(\T currInd/)).\T table/[k])$\\
2273:
2274: %\\ ! G-migrate3-1-a!\\
2275: \S Ne12:/ \>$ k < \S curSize/\Land \T H/(\T currInd/).\T table/[k]=\B done/\Land m< h.\T size/$\\
2276: \>$\land\;\; \S LeastFind/(h,a,m) $\\
2277: \> $ \implies\quad \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)])$, \\
2278: \> where $a=\S ADR/(\T Y/[k])$ and $h=\T H/(\T next/(\T currInd/)))$\\
2279:
2280: %\\ ! G-migrate3-1-b!\\
2281: \S Ne13:/ \>$k < \S curSize/\Land \T H/(\T currInd/).\T table/[k]=\B done/\Land m <h.\T size/$\\
2282: \> $\land\;\; \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)])
2283: \neq \B null/$\\
2284: \> $\implies\quad \S LeastFind/(h,a,m)$,\\
2285: \> where $a=\S ADR/(\T Y/[k])$ and $h=\T H/(\T next/(\T currInd/))$\\
2286:
2287: %\\ ! G-migrate3-2!\\
2288: \S Ne14:/ \>$\T next/(\T currInd/)\neq 0 \Land a\neq \B 0/ \Land k < h.\T size/$\\
2289: \>$\land\;\; \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,k)])
2290: \neq\B null/$\\
2291: \>$\implies\quad \S LeastFind/(h,a,k)$,\\
2292: \>where $h=\T H/(\T next/(\T currInd/))$\\
2293:
2294: %\\ ! G-migrate5-1!\\
2295: \S Ne15:/ \>$k < \S curSize/\Land \T H/(\T currInd/).\T table/[k]=\B done/\Land \T X/(a)\neq \B null/$\\
2296: \>$ \land\;\; m < h.\T size/\Land \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)])$\\
2297: \>$ \land\;\; n < h.\T size/ \Land m \ne n $ \\
2298: \> $\implies\quad \S ADR/(h.\T table/.[\S key/(a,h.\T size/,n)])\ne a$,\\
2299: \>where $ a=\S ADR/(\T Y/[k])$ and $h=\T H/(\T next/(\T currInd/))$\\
2300:
2301: %\\ ! G-migrate5-1!\\
2302: \S Ne16:/ \>$k < \S curSize/\Land \T H/(\T currInd/).\T table/[k]=\B done/\Land \T X/(a)= \B null/ $\\
2303: \>$\land\;\; m < h.\T size/$\\
2304: \>$\implies\quad \S val/(h.\T table/[\S key/(a,h.\T size/,m)]) = \B null/$\\
2305: \>\>$\lor\;\; \S ADR/(h.\T table/[\S key/(a,h.\T size/,m)])\ne a $, \\
2306: \>where $ a=\S ADR/(\T Y/[k])$ and $h=\T H/(\T next/(\T currInd/))$\\
2307:
2308:
2309: %\\ ! G-migrate5-2!\\
2310: \S Ne17:/ \>$ \T next/(\T currInd/)\neq 0\Land m < h.\T size/\Land a=\S ADR/(h.\T table/[m])\ne 0 $\\
2311: \> $ \implies\quad \T X/(a)=\S val/(h.\T table/[m]) \neq \B null/$, \\
2312: \>where $h=\T H/(\T next/(\T currInd/))$\\
2313:
2314: %\\ ! G-migrate5-2!\\
2315: \S Ne18:/ \>$ \T next/(\T currInd/)\neq 0\Land m < h.\T size/\Land a = \S ADR/(h.\T table/[m]) \ne 0 $\\
2316: \> $ \implies\quad \exists n < \S curSize/: \S val/(\T Y/[n])=\S val/(h.\T table/[m]) $\\
2317: \>\>$\land\;\; \S oldp/(\T H/(\T currInd/).\T table/[n])$, \\
2318: \>where $h=\T H/(\T next/(\T currInd/))$\\
2319:
2320: %\\ ! G-migrate5-3!\\
2321: \S Ne19:/ \>$ \T next/(\T currInd/)\neq 0 \Land m < h.\T size/ \Land m \ne n < h.\T size/$ \\
2322: \> $ \land\;\; a = \S ADR/(h.\T table/[\S key/(a,h.\T size/,m)])\ne 0 $\\
2323: \> $ \implies\quad \S ADR/(h.\T table/[\S key/(a,h.\T size/,n)])\ne a $,\\
2324: \>where $h=\T H/(\T next/(\T currInd/))$\\
2325:
2326: %\\ ! G-migrate6-4!\\
2327: \S Ne20:/ \>$ k < \S curSize/\Land
2328: \T H/(\T currInd/).\T table/[k]=\B done/ \Land \T X/(a)\neq \B null/$\\
2329: \>$\implies \quad \exists m < h.\T size/:
2330: \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)])$,\\
2331: \>where $a=\S ADR/(\T Y/ [k])$ and $ h=\T H/(\T next/(\T currInd/))$\\
2332:
2333: %\\ ! G-nextocc!\\
2334: \S Ne21:/ \>\S Ne21/ has been eliminated.\\
2335:
2336: %\\ ! G-nextocc2!\\
2337: \S Ne22:/ \>$ \T next/(\T currInd/)\neq 0~$\\
2338: \>$\implies \quad \sharp (\S ocSet6/)=\T H/(\T next/(\T currInd/)).\T occ/+\sharp (ocSet7)$\\
2339:
2340: %\\ ! G-nextocc1!\\
2341: \S Ne23:/ \>$ \T next/(\T currInd/)\neq 0~$\\
2342: \>$\implies \quad \T H/(\T next/(\T currInd/)).\T occ/\leq\T H/(\T next/(\T currInd/)).\T bound/$ \\
2343:
2344: %\\ ! G-nextinj3!\\
2345: \S Ne24:/ \>$ \T next/(\T currInd/)\neq 0~\implies \quad
2346: \sharp (\S ocSet5/)\leq \sharp (\S ocSet4/)$ \\
2347:
2348: %\\ ! G-nextbij!\\
2349: \S Ne25:/ \>$~~~ \T next/(\T currInd/)\neq 0$\\
2350: \>$\implies \quad \exists $\=$(f:[$\=$\{m:0\leq m<h.\T size/\land \S val/(h.\T table/[m])\neq \B null/\}\rightarrow $\\
2351: \>\>$\{v:v\neq\B null/\land (\exists k<h.\T size/:v=\S val/(h.\T table/[k]))\}]):$\\
2352: \>\>$f~ \T is bijective/$, \\
2353: \>where $h=\T H/(\T next/(\T currInd/))$\\
2354:
2355: %\\ ! G-nextinj1!\\
2356: \S Ne26:/ \>$~~~ \T next/(\T currInd/)\neq 0$\\
2357: \>$\implies \quad \exists $\=$(f:[$\=$\{v:v\neq\B null/
2358: \land (\exists m<h.\T size/:v=\S val/(h.\T table/[m]))\}\rightarrow $\\
2359: \>\>\>$\{v:v\neq\B null/\land (\exists k:<\S curSize/:v=\S val/(\T Y/[k]))\}]):$\\
2360: \>\>$f~ \T is injective/$, \\
2361: \>where $h=\T H/(\T next/(\T currInd/))$\\
2362:
2363: %\\ ! G-nextinj2!\\
2364: \S Ne27:/ \>$~~~ \T next/(\T currInd/)\neq 0 \Land (\exists n<h.\T size/: \S val/(h.\T table/[n])\neq \B null/)$\\
2365: \>$\implies \quad \exists $\=$(f:[$\=$\{m:0\leq m<h.\T size/\land \S val/(h.\T table/[m]) \neq \B null/\} \rightarrow $\\
2366: \>\>\>$\{k:0\leq k<\S curSize/\land \S val/(\T Y/[k])\neq \B null/\}])$\\
2367: \>\>$f~ \T is injective/$, \\
2368: \>where $h=\T H/(\T next/(\T currInd/))$
2369: \end{tab1}
2370:
2371:
2372: \medbreak Invariants concerning procedure \S find/ (5\dots 14)
2373: \begin{tab1}
2374:
2375: %\\ ! G-a-a!\\
2376: \S fi1:/ \>$a_{\it fi}\neq \B 0/$ \\
2377:
2378: %\\ ! G-n-find1!\\
2379: \S fi2:/ \>$ pc\in \{6,11\}~\implies \quad n_{\it fi}=0$ \\
2380:
2381:
2382: %\\ ! G-find4!\\
2383: \S fi3:/ \>$ pc \in \{7,8,13\} ~\implies \quad l_{\it fi}=h_{\it fi}.\T size/$ \\
2384:
2385: %\\ ! G-find5!\\
2386: \S fi4:/ \>$ pc \in [6,13]\Land pc\neq 10~\implies \quad h_{\it fi}=\T H/(\S index/)$ \\
2387:
2388:
2389: %\\ ! G-n-size-a!\\
2390: \S fi5:/ \>$ pc=7 \Land h_{\it fi}=\T H/(\T currInd/)~\implies \quad
2391: n_{\it fi} < \S curSize/$ \\
2392:
2393: %\\ ! G-r-find2!\\
2394: \S fi6:/ \>$ pc=8\Land h_{\it fi}=\T H/(\T currInd/)\Land\neg \S Find/(r_{\it fi},a_{\it fi})
2395: \Land r_{\it fi}\neq\B done/$\\
2396: \>$\implies\ \neg\ \S Find/(\T Y/[\S key/(a_{\it fi},\S curSize/,n_{\it fi})],
2397: a_{\it fi})$ \\
2398:
2399: %\\ ! G-r-find1!\\
2400: \S fi7:/ \>$ pc=13 \Land h_{\it fi}=\T H/(\T currInd/)\Land \neg\S Find/(r_{\it fi},a_{\it fi})
2401: \Land m < n_{\it fi}$ \\
2402: \> $ \implies\quad \neg\S Find/(\T Y/[\S key/(a_{\it fi},\S curSize/,m)], a_{\it fi})$ \\
2403:
2404: %\\ ! G-find3!\\
2405: \S fi8:/ \>$ pc\in \{7,8\}\Land h_{\it fi}=\T H/(\T currInd/) \Land m < n_{\it fi}$\\
2406: \> $ \implies\quad
2407: \neg \S Find/(\T Y/[\S key/(a_{\it fi},\S curSize/,m)],a_{\it fi})$ \\
2408:
2409: %\\ ! G-find2!\\
2410: \S fi9:/ \>$ $\=$pc=7\Land\S Find/(t,a_{\it fi})~\implies \quad \T X/(a_{\it fi})=\S val/(t)$, \\
2411: \>where $t=h_{\it fi}.\T table/[\S key/(a_{\it fi},l_{\it fi},n_{\it fi})]$\\
2412:
2413: %\\ ! G-find1!\\
2414: \S fi10:/ \>$ pc \notin (1,7] \Land \S Find/(r_{\it fi},a_{\it fi})~\implies \quad
2415: \S val/(r_{\it fi})=rS_{\it fi} $ \\
2416:
2417: %\\ ! G-old-a!\\
2418: \S fi11:/ \>$pc=8\Land \S oldp/(r_{\it fi})\Land \S index/=\T currInd/$\\
2419: \>$\implies\ \T next/(\T currInd/)\neq 0$
2420: \end{tab1}
2421:
2422:
2423: \medbreak Invariants concerning procedure \S delete/ (15\dots 26)
2424: \begin{tab1}
2425:
2426: %\\ ! G-a-b!\\
2427: \S de1:/ \>$a_{\it del}\neq \B 0/$ \\
2428:
2429: %\\ ! G-delete4!\\
2430: \S de2:/ \>$ pc \in\{17,18\}~\implies \quad l_{\it del}=h_{\it del}.\T size/$ \\
2431:
2432: %\\ ! G-delete5!\\
2433: \S de3:/ \>$ pc\in [16,25] \Land pc\neq 20~\implies \quad h_{\it del}=\T H/(\S index/)$ \\
2434:
2435: %\\ ! G-find7-a!\\
2436: \S de4:/ \>$ pc=18~\implies \quad k_{\it del}=\S key/(a_{\it del},l_{\it del},n_{\it del})$ \\
2437:
2438: %\\ ! G-s-delete1!\\
2439: \S de5:/ \>$ pc\in \{16,17\} \Lor \S Deleting/ ~\implies \quad \neg suc_{\it del}$\\
2440:
2441: %\\ ! G-s-delete2!\\
2442: \S de6:/ \> $ \S Deleting/ \Land sucS_{\it del}~\implies \quad r_{\it del}\neq \B null/$ \\
2443:
2444: %\\ ! G-find6-a!\\
2445: \S de7:/ \>$ pc=18\Land \neg\ \S oldp/(h_{\it del}.\T table/[k_{\it del}])~\implies \quad
2446: h_{\it del}=\T H/(\T currInd/)$ \\
2447:
2448: %\\ ! G-n-size-b!\\
2449: \S de8:/ \>$ pc \in \{17,18\} \Land h_{\it del}=\T H/(\T currInd/)~\implies \quad
2450: n_{\it del}<\S curSize/$\\
2451:
2452: %\\ ! G-r-delete1!\\
2453: \S de9:/ \>$pc=18\Land h_{\it del}=\T H/(\T currInd/)$\\
2454: \>$\land~ (\S val/(r_{\it del})\neq\B null/\Lor r_{\it del}=\B del/)$\\
2455: \>$\implies\ r\neq \B null/\Land (r=\B del/\Lor
2456: \S ADR/(r)=\S ADR/(r_{\it del}))$,\\
2457: \>where $r=\T Y/[\S key/(a_{\it del},h_{\it del}.size,n_{\it del})]$\\
2458:
2459: %\\ ! G-delete3!\\
2460: \S de10:/ \>$ pc\in\{17,18\}\Land h_{\it del}=\T H/(\T currInd/) \Land m < n_{\it del}) $\\
2461: \> $ \implies\quad \neg \S Find/(\T Y/[\S key/(a_{\it del},\S curSize/,m)],a_{\it del})$\\
2462:
2463: %\\ ! G-delete2!\\\
2464: \S de11:/ \>$ pc\in \{17,18\} \Land \S Find/(t,a_{\it del})~\implies \quad
2465: \T X/(a_{\it del})=\S val/(t)$,\\
2466: \>where $t=h_{\it del}.\T table/[\S key/(a_{\it del},l_{\it del},n_{\it del})]$\\
2467:
2468: %\\ ! G-old-b!\\
2469: \S de12:/ \>$pc=18\Land \S oldp/(r_{\it del})\Land \S index/=\T currInd/$\\
2470: \>$\implies\ \T next/(\T currInd/)\neq 0$ \\
2471:
2472: %\\ ! G-find6-1-a!\\
2473: \S de13:/ \>$ pc=18~\implies \quad k_{\it del}<\T H/(\S index/).\T size/$ \\
2474: %\>;\qquad ELIMINATED by (fi7-a),(del4),(del5) and axiom (KEYinRange).
2475: \end{tab1}
2476:
2477: \medbreak\noindent
2478: where $Deleting$ is characterized by
2479: \begin{tab1}
2480: \+ $\S Deleting/\EQ $\\
2481: $pc\in [18,21]\Lor pc\in [59,65]\Land return_{\it gA}=20$\\
2482: $\lor~ pc\in [67,72]\Land ($\=$return_{\it rA}=59 \land
2483: return_{\it gA}=20$\\
2484: \>$\lor~ return_{\it rA}=90 \land return_{\it ref}=20)$\\
2485: $\lor\ pc\geq 90 \Land return_{\it ref}=20$
2486: \end{tab1}
2487:
2488: \medbreak Invariants concerning procedure \S insert/ (27\dots 52)
2489:
2490: \begin{tab1}
2491: %\\ ! G-a-c!\\
2492: \S in1:/ \>$a_{\it ins}=\S ADR/(v_{\it ins})\Land v_{\it ins}\neq \B null/$ \\
2493:
2494: %\\ ! G-insert4!\\
2495: \S in2:/ \>$pc\in [32,35]~\implies \quad l_{\it ins}=h_{\it ins}.\T size/$ \\
2496:
2497: %\\ ! G-insert5!\\
2498: \S in3:/ \>$pc\in [28,41]\Land pc\notin \{30,36\}~\implies \quad h_{\it ins}=\T H/(\S index/)$ \\
2499:
2500: %\\ ! G-find7-b!\\
2501: \S in4:/ \>$ pc\in \{33,35\}~\implies \quad
2502: k_{\it ins}=\S key/(a_{\it ins},l_{\it ins},n_{\it ins})$ \\
2503:
2504: %\\ ! G-s-insert1!\\
2505: \S in5:/ \>$pc\in [32,33]\Lor \S Inserting/ ~\implies \quad \neg suc_{\it ins}$\\
2506:
2507: %\\ ! G-s-insert2!\\
2508: \S in6:/ \> $\S Inserting/\Land sucS_{\it ins}~\implies \quad
2509: \S ADR/(r_{\it ins})\neq a_{\it ins}$\\
2510:
2511: %\\ ! G-find6-b!\\
2512: \S in7:/ \>$ pc=35\Land \neg\ \S oldp/(h_{\it ins}.\T table/[k_{\it ins}])~\implies \quad
2513: h_{\it ins}=\T H/(\T currInd/)$ \\
2514:
2515: %\\ ! G-n-size-c!\\
2516: \S in8:/ \>$ pc \in \{33,35\} \Land h_{\it ins}=\T H/(\T currInd/)~\implies \quad n_{\it ins}<\S curSize/$\\
2517:
2518: %\\ ! G-r-insert1!\\
2519: \S in9:/ \>$pc=35\Land h_{\it ins}=\T H/(\T currInd/)$\\
2520: \>$\land~ (\S val/(r_{\it ins})\neq\B null/\Lor r_{\it ins}=\B del/)$\\
2521: \>$\implies\ r\neq \B null/\Land (r=\B del/\Lor \S ADR/(r)=\S ADR/(r_{\it ins}))$,\\
2522: \>where $r=\T Y/[\S key/(a_{\it ins},h_{\it ins}.size,n_{\it ins})]$\\
2523:
2524: %\\ ! G-insert3!\\
2525: \S in10:/ \>$pc\in \{32,33,35\}\Land h_{\it ins}=\T H/(\T currInd/) \Land m < n_{\it ins} $\\
2526: \>$ \implies\quad \neg \S Find/(\T Y/[\S key/(a_{\it ins},\S curSize/,m)],a_{\it ins})$\\
2527:
2528: %\\ ! G-insert2!\\
2529: \S in11:/ \>$pc\in \{ 33,35\}\Land \S Find/(t,a_{\it ins})~\implies \quad\ \T X/(a_{\it ins})=\S val/(t)$,\\
2530: \>where $t=h_{\it ins}.\T table/[\S key/(a_{\it ins},l_{\it ins},n_{\it ins})]$ \\
2531:
2532: %\\ ! G-old-c!\\
2533: \S in12:/ \>$pc=35\Land \S oldp/(r_{\it ins})\Land \S index/=\T currInd/$\\
2534: \>$\implies\ \T next/(\T currInd/)\neq 0$ \\
2535:
2536: %\\ ! G-find6-1-b!\\
2537: \S in13:/ \>$ pc=35~\implies \quad k_{\it ins}<\T H/(\S index/).\T size/$ \\
2538: %\>;\qquad ELIMINATED by (fi7-b),(in4),(in5) and axiom (KEYinRange).
2539: \end{tab1}
2540: where $Inserting$ is characterized by
2541: \begin{tab1}
2542: \+ $\S Inserting/ \EQ $\\
2543: $pc\in [35,37]\Lor pc\in [59,65]\Land return_{\it gA}=36$\\
2544: $\lor~ pc\in [67,72]\Land ($\=$return_{\it rA}=59 \land
2545: return_{\it gA}=36$\\
2546: \>$\lor~ return_{\it rA}=90 \land return_{\it ref}=36)$\\
2547: $\lor~ pc\geq 90 \Land return_{\it ref}=36$
2548: \end{tab1}
2549:
2550:
2551: \medbreak Invariants concerning procedure \S assign/ (43\dots 57)
2552:
2553: \begin{tab1}
2554: %\\ ! G-a-d!\\
2555: \S as1:/ \>$ a_{\it ass}=\S ADR/(v_{\it ass})\Land v_{\it ass}\neq \B null/$ \\
2556:
2557: %\\ ! G-assign4!\\
2558: \S as2:/ \>$pc\in [48,50]~\implies \quad l_{\it ass}=h_{\it ass}.\T size/$ \\
2559:
2560: %\\ ! G-assign5!\\
2561: \S as3:/ \>$pc\in [44,57]\Land pc\notin \{46,51\}~\implies \quad h_{\it ass}=\T H/(\S index/)$ \\
2562:
2563: %\\ ! G-find7-c!\\
2564: \S as4:/ \>$ pc\in \{49,50\}~\implies \quad
2565: k_{\it ass}=\S key/(a_{\it ass},l_{\it ass},n_{\it ass})$\\
2566:
2567: %\\ ! G-find6-c!\\
2568: \S as5:/ \>$ pc=50\Land \neg\ \S oldp/(h_{\it ass}.\T table/[k_{\it ass}])~\implies \quad h_{\it ass}=\T H/(\T currInd/)$\\
2569:
2570: %\\ ! G-n-size-d!\\
2571: \S as6:/ \>$ pc = 50 \Land h_{\it ass}=\T H/(\T currInd/)~\implies \quad n_{\it ass}<\S curSize/$ \\
2572:
2573: %\\ ! G-r-assign1!\\
2574: \S as7:/ \>$pc=50\Land h_{\it ass}=\T H/(\T currInd/)$\\
2575: \>$\land~ (\S val/(r_{\it ass})\neq\B null/\Lor r_{\it ass}=\B del/)$\\
2576: \>$\implies\ r\neq \B null/\Land (r=\B del/\Lor \S ADR/(r)=\S ADR/(r_{\it ass}))$,\\
2577: \>where $r=\T Y/[\S key/(a_{\it ass},h_{\it ass}.size,n_{\it ass})]$ \\
2578:
2579: %\\ ! G-assign3!\\
2580: \S as8:/ \>$pc\in \{48,49,50\}\Land h_{\it ass}=\T H/(\T currInd/) \Land m < n_{\it ass} $\\
2581: \> $ \implies\quad \neg \S Find/(\T Y/[\S key/(a_{\it ass},\S curSize/,m)],a_{\it ass})$\\
2582:
2583: %\\ ! G-assign2!\\
2584: \S as9:/ \>$pc=50 \Land \S Find/(t,a_{\it ass})~\implies \quad \T X/(a_{\it ass})=\S val/(t)$,\\
2585: \>where $t=h_{\it ass}.\T table/[\S key/(a_{\it ass},l_{\it ass},n_{\it ass})]$\\
2586:
2587: %\\ ! G-old-d!\\
2588: \S as10:/ \>$pc=50\Land \S oldp/(r_{\it ass}sign)\Land \S index/=\T currInd/$\\
2589: \>$\implies\ \T next/(\T currInd/)\neq 0$ \\
2590:
2591: %\\ ! G-find6-1-c!\\
2592: \S as11:/ \>$ pc=50~\implies \quad k_{\it ass}<\T H/(\S index/).\T size/$ \\
2593: %\>;\qquad ELIMINATED by (fi7-c),(as4),(as5) and axiom (KEYinRange).
2594: \end{tab1}
2595:
2596:
2597: \medbreak Invariants concerning procedure \S releaseAccess/ (67\dots 72)
2598:
2599: \begin{tab1}
2600:
2601: %\\ ! G-H-index2!\\
2602: \S rA1:/ \>$ h_{\it rA}<\T H/_-\T index/$\\
2603:
2604: %\\ ! G-H6!\\
2605: \S rA2:/ \>$ pc\in [70,71]~\implies \quad h_{\it rA}\neq 0$ \\
2606:
2607: %\\ ! G-releaseAccess6!\\
2608: \S rA3:/ \>$pc=71 ~\implies \quad \T Heap/(h_{\it rA})\neq\bot$ \\
2609:
2610: %\\ ! G-H3!\\
2611: \S rA4:/ \>$ pc=71~\implies \quad \T H/(i_{\it rA})=0$ \\
2612:
2613: %\\ ! G-H7!\\
2614: \S rA5:/ \>$ pc=71~\implies \quad h_{\it rA}\ne\T H/(i)$ \\
2615:
2616: %\\ ! G-releaseAccess1-a!\\
2617: \S rA6:/ \>$pc=70~\implies \quad\T H/(i_{\it rA})\neq\T H/(\T currInd/)$ \\
2618:
2619: %\\ ! G-releaseAccess1-b!\\
2620: \S rA7:/ \>$pc=70$\\
2621: \>$\land\ (pc.r \in [1,58]\Lor pc.r>65\land
2622: \neg (pc.r \in [67,72]\land i_{\it rA}.r=\S index/.r))$\\
2623: \>$\implies\ \T H/(i_{\it rA})\neq \T H/(\S index/.r)$\\
2624:
2625: %\\ ! G-i-releaseAccess1!\\
2626: \S rA8:/ \>$pc=70~\implies \quad i_{\it rA}\neq\T next/(\T currInd/)$ \\
2627:
2628: %\\ ! G-releaseAccess2!\\
2629: \S rA9:/ \>$pc\in [68,72]\land\ (h_{\it rA}=0\Lor h_{\it rA}\neq \T H/(i_{\it rA}))$\\
2630: \> $\implies\ \T H/(i_{\it rA})=0$ \\
2631:
2632: %\\ ! G-i-releaseAccess2!\\
2633: \S rA10:/ \>$pc\in [67,72]\Land return_{\it rA}\in \{0,59\}~\implies\ i_{\it rA}=\S index/$\\
2634:
2635: %\\ ! G-releaseAccess3!\\
2636: \S rA11:/ \>$pc\in [67,72]\Land return_{\it rA}\in \{77,90\}~\implies\ i_{\it rA}\neq \S index/$ \\
2637:
2638: %\\ ! G-releaseAccess5!\\
2639: \S rA12:/ \>$pc\in [67,72]\Land return_{\it rA}=77~\implies \quad\T next/(\S index/)\neq 0$ \\
2640:
2641:
2642: %\\ ! G-releaseAccess8!\\
2643: \S rA13:/ \>$pc=71 \Land pc.r=71 \Land p\neq r ~\implies \quad h_{\it rA}\neq h_{\it rA}.r$ \\
2644:
2645: %\\ ! G-i-releaseAccess3!\\
2646: \S rA14:/ \>$pc=71 \Land pc.r=71 \Land p\neq r ~\implies \quad i_{\it rA}\neq i_{\it rA}.r$
2647: \end{tab1}
2648:
2649:
2650: \medbreak Invariants concerning procedure \S newTable/ (77\dots 84)
2651:
2652: \begin{tab1}
2653:
2654: %\\ ! G-newTable9!\\
2655: \S nT1:/ \>$ pc \in [81,82] ~\implies \quad \T Heap/(\T H/(i_{\it nT}))=\bot$ \\
2656:
2657: %\\ ! G-newTable2!\\
2658: \S nT2:/ \>$ pc \in [83,84]~\implies \quad \T Heap/(\T H/(i_{\it nT}))\neq \bot$ \\
2659:
2660:
2661: %\\ ! G-next-i-newTable!\\
2662: \S nT3:/ \>$ pc=84 ~\implies \quad\T next/(i_{\it nT})=0$ \\
2663:
2664: %\\ ! G-newTable4!\\
2665: \S nT4:/ \>$ pc \in [83,84] ~\implies \quad \T H/(i_{\it nT}).\T dels/=0$ \\
2666:
2667: %\\ ! G-newTable6!\\
2668: \S nT5:/ \>$ pc \in [83,84] ~\implies \quad \T H/(i_{\it nT}).\T occ/=0$ \\
2669:
2670: %\\ ! G-newTable7!\\
2671: \S nT6:/ \>$ pc \in [83,84] ~\implies \quad
2672: \T H/(i_{\it nT}).\T bound/+2*P< \T H/(i_{\it nT}).\T size/$ \\
2673:
2674: %\\ ! G-newTable8!\\
2675: \S nT7:/ \>$ pc \in [83,84] \Land \S index/=\T currInd/$\\
2676: \>$\implies \quad \T H/(\T currInd/).\T bound/-\T H/(\T currInd/).\T dels/+2*P< \T H/(i_{\it nT}).\T bound/$ \\
2677:
2678: %\\ ! G-newTable5!\\
2679: \S nT8:/ \>$ pc \in [83,84]\Land k < \T H/(i_{\it nT}).\T size/
2680: ~\implies \quad \T H/(i_{\it nT}).\T table/[k]=\B null/$ \\
2681:
2682: %\\ ! G-i-newTable-a!\\
2683: \S nT9:/ \>$ pc \in [81,84]~\implies \quad i_{\it nT}\neq \T currInd/$ \\
2684:
2685: %\\ ! G-i-newTable-b!\\
2686: \S nT10:/ \>$ pc \in [81,84]\Land (pc.r\in [1,58]\Lor pc.r\geq 62 \Land pc.r\neq 65) $\\
2687: \>$\implies\quad i_{\it nT}\ne \S index/.r$\\
2688:
2689: %\\ ! G-i-newTable4!\\
2690: \S nT11:/ \>$ pc\in [81,84]~\implies \quad i_{\it nT}\neq \T next/(\T currInd/)$\\
2691:
2692: %\\ ! G-newTable1-a!\\
2693: \S nT12:/ \>$ pc \in [81,84]~\implies \quad\T H/(i_{\it nT})\neq \T H/(\T currInd/)$\\
2694: %\>;\qquad ELIMINATED by (i-nT-a),(k0-a),(h1).
2695:
2696: %\\ ! G-newTable1-b!\\
2697: \S nT13:/ \>$ pc \in [81,84]$\\
2698: \>$\land\ (pc.r \in [1,58]\Lor pc.r>65\land \neg (pc.r \in [67,72]\land i_{\it rA}.r=\S index/.r))$\\
2699: \>$\implies\quad \T H/(i_{\it nT})\ne \T H/(\S index/.r)$ \\
2700:
2701: %\\ ! G-i-newTable2!\\
2702: \S nT14:/ \>$ pc\in [81,84]\Land pc.r\in [67,72]~\implies \quad
2703: i_{\it nT}\ne i_{\it rA}.r$\\
2704:
2705: %\\ ! G-newTable3!\\
2706: \S nT15:/ \>$ pc \in [83,84]\Land pc.r\in [67,72]~\implies \quad
2707: \T H/(i_{\it nT})\ne \T H/(i_{\it rA}.r)$ \\
2708:
2709: %\\ ! G-i-newTable3!\\
2710: \S nT16:/ \>$ pc\in [81,84]\Land pc.r\in [81,84]\Land p \ne r
2711: ~\implies \quad i_{\it nT}\ne i_{\it nT}.r$ \\
2712:
2713: %\\ ! G-i-newTable5!\\
2714: \S nT17:/ \>$ pc\in [81,84]\Land pc.r \in [95,99]\Land \S index/.r=\T currInd/$\\
2715: \> $\implies\quad i_{\it nT}\ne i_{\it mig}.r$\\
2716:
2717: %\\ ! G-i-newTable1!\\
2718: \S nT18:/ \>$ pc\in [81,84]\Land pc.r\geq 99~\implies \quad i_{\it nT}\ne i_{\it mig}.r$
2719: \end{tab1}
2720:
2721:
2722: \medbreak Invariants concerning procedure \S migrate/ (94\dots 105)
2723:
2724: \begin{tab1}
2725:
2726: %\\ ! G-migrate8,G-index1 !\\
2727: \S mi1:/ \>$ pc=98 \Lor pc\in \{104,105\} ~\implies \quad \S index/\neq \T currInd/$\\
2728:
2729: %\\ ! G-i-migrate1!\\
2730: \S mi2:/ \>$ pc\geq 95~\implies \quad i_{\it mig}\neq \S index/$ \\
2731:
2732: %\\ ! G-i-migrate6!\\
2733: \S mi3:/ \>$ pc=94~\implies \quad \T next/(\S index/)>0$\\
2734:
2735: %\\ ! G-i-migrate4!\\
2736: \S mi4:/ \>$ pc\geq 95~\implies \quad i_{\it mig}\neq 0$\\
2737:
2738: %\\ ! G-i-migrate3!\\
2739: \S mi5:/ \>$ pc \geq 95~\implies \quad i_{\it mig}=\T next/(\S index/)$ \\
2740:
2741: %\\ ! G-i-migrate2, G-i-migrate7!\\
2742: \S mi6:/ \>$ pc.r=70$\\
2743: \>$\land~ (pc\in [95,102) \Land \S index/=\T currInd/ \Lor pc \in [102,103] \Lor pc\geq 110)$\\
2744: \>$\implies \quad i_{\it rA}.r\neq i_{\it mig}$ \\
2745:
2746: %\\ ! G-next-i-migrate,G-next-i-migrate1!\\
2747: \S mi7:/ \>$ pc \in [95,97]\Land \S index/=\T currInd/\Lor pc\geq 99$\\
2748: \>$\implies \quad i_{\it mig}\neq \T next/(i_{\it mig})$\\
2749:
2750: %\\ ! G-next-i-migrate2!\\
2751: \S mi8:/ \>$ (pc \in [95,97]\Lor pc \in [99,103] \Lor pc\geq 110)\Land \S index/=\T currInd/$\\
2752: \>$\implies \quad \T next/(i_{\it mig})=0$\\
2753:
2754: %\\ ! G-i-migrate-a !\\
2755: \S mi9:/ \>$(pc \in [95,103]\Lor pc\geq 110)\Land \S index/=\T currInd/$ \\
2756: \>\>$\implies \quad \T H/(i_{\it mig})\neq \T H/(\T currInd/)$\\
2757:
2758: %\\ ! G-i-migrate-b !\\
2759: \S mi10:/ \>$(pc \in [95,103]\Lor pc\geq 110)\Land \S index/=\T currInd/ $ \\
2760: \> $ \land\;\; (pc.r \in [1,58]\Lor pc.r\geq 62\Land pc.r\neq 65)$\\
2761: \>$\implies\quad \T H/(i_{\it mig}) \neq \T H/(\S index/.r) $ \\
2762:
2763: %\\ ! G-moveContents9-1!\\
2764: \S mi11:/ \>$ pc=101 \Land \S index/=\T currInd/ \Lor pc=102$\\
2765: \>$\implies \quad h_{\it mig}=\T H/(i_{\it mig})$\\
2766:
2767: %\\ ! G-migrate2,G-migrate2-1!\\
2768: \S mi12:/ \>$pc\geq 95\Land \S index/=\T currInd/ \Lor pc\in \{102,103\}\Lor pc\geq 110$\\
2769: \>$\implies \quad\ \T Heap/(\T H/(i_{\it mig}))\neq \bot$ \\
2770:
2771: %\\ ! G-migrate1!\\
2772: \S mi13:/ \>$pc=103\Land \S index/=\T currInd/\Land k < \S curSize/~$\\
2773: \>$\implies \quad \T H/(\S index/).\T table/[k]=\B done/$\\
2774:
2775: %\\ ! G-migrate3-a!\\
2776: \S mi14:/ \>$$\=$pc=103\Land \S index/=\T currInd/\Land n < \T H/(i_{\it mig}).\T size/$\\
2777: \>\>$\land\quad \S LeastFind/(\T H/(i_{\it mig}),a,n)$\\
2778: \>\>$\implies\quad \T X/(a)=\S val/(\T H/(i_{\it mig})[\S key/(a,\T H/(i_{\it mig}).\T size/,n)])$ \\
2779:
2780: %\\ ! G-migrate3-b!\\
2781: \S mi15:/ \>$$\=$pc=103\Land \S index/=\T currInd/\Land n < \T H/(i_{\it mig}).\T size/$\\
2782: \>\>$\land\quad \T X/(a)=
2783: \S val/(\T H/(i_{\it mig}).\T table/[\S key/(a,\T H/(i_{\it mig}).\T size/,n)]
2784: \neq\B null/$\\
2785: \>\>$\implies\quad \S LeastFind/(\T H/(i_{\it mig}),a,n)$ \\
2786:
2787: %\\ ! G-migrate4\\!\\
2788: \S mi16:/ \>$pc=103\Land \S index/=\T currInd/\Land k < \T H/(i_{\it mig}).\T size/$\\
2789: \>$ \implies\quad \neg \S oldp/(\T H/(i_{\it mig}).\T table/[k])$\\
2790:
2791: %\\ ! G-migrate5-a!\\
2792: \S mi17:/ \>$pc=103\Land \S index/=\T currInd/ \Land \T X/(a)\neq \B null/\Land
2793: k < h.\T size/$\\
2794: \> $ \land\;\; \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,k)])
2795: \Land k \ne n < h.\T size/$\\
2796: \> $\implies\quad \S ADR/(h.\T table/.[\S key/(a,h.\T size/,n)])\ne a $,\\
2797: \>where $ h=\T H/(i_{\it mig})$ \\
2798:
2799: %\\ ! G-migrate5-b!\\
2800: \S mi18:/ \>$pc=103\Land \S index/=\T currInd/ \Land \T X/(a)=\B null/\Land k < h.\T size/$\\
2801: \>$ \implies\quad \S val/(h.\T table/[\S key/(a,h.\T size/,k)]) = \B null/$\\
2802: \>\>$\Lor~ \S ADR/(h.\T table/[\S key/(a,h.\T size/,k)])\ne a $, \\
2803: \>where $ h=\T H/(i_{\it mig})$\\
2804:
2805: %\\ ! G-migrate6!\\
2806: \S mi19:/ \>$ pc=103\Land \S index/=\T currInd/\Land \T X/(a)\neq \B null /$\\
2807: \> $ \implies\quad \exists m < h.\T size/:
2808: \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)]$, \\
2809: \>where $h=\T H/(i_{\it mig})$\\
2810:
2811: %\\ ! G-migrate6-3!\\
2812: \S mi20:/ \>$ $\=$pc=117 \Land \T X/(a)\neq \B null/
2813: \Land \S val/(\T H/(\S index/).\T table/[i_{\it mC}])\neq \B null/$\\
2814: \>$\lor~ pc\geq 126\Land \T X/(a)\neq \B null/\Land \S index/=\T currInd/$\\
2815: \>$\lor~ pc=125 \Land \T X/(a)\neq \B null/\Land \S index/=\T currInd/$\\
2816: \>\>$ \Land $\=$(b_{\it mE} \Lor \S val/(w_{\it mE})\neq \B null/$\\
2817: \>\>\>$\Land a_{\it mE}=\S ADR/(w_{\it mE}))$ \\
2818: \>$\implies\ \exists m < h.\T size/:
2819: \T X/(a)=\S val/(h.\T table/[\S key/(a,h.\T size/,m)])$,\\
2820: \>where $a=\S ADR/(\T Y/[i_{\it mC}])$ and $h=\T H/(\T next/(\T currInd/))$
2821: \end{tab1}
2822:
2823:
2824: \medbreak Invariants concerning procedure \S moveContents/ (110\dots 118):
2825: \begin{tab1}
2826:
2827: %\\ ! G-moveContents9!\\
2828: \S mC1:/ \>$ pc=103 \Lor pc \geq 110~\implies \quad to=\T H/(i_{\it mig})$\\
2829:
2830: %\\ ! G-moveContents1!\\
2831: \S mC2:/ \>$ pc\geq 110~\implies \quad from=\T H/(\S index/)$\\
2832:
2833: %\\ ! G-moveContents11!\\
2834: \S mC3:/ \>$ pc>102\Land m \in toBeMoved~\implies \quad m<\T H/(\S index/).\T size/$\\
2835:
2836:
2837: %\\ ! G-moveContents10!\\
2838: \S mC4:/ \>$ pc=111~\implies \quad \exists m < from.\T size/:m\in toBeMoved$ \\
2839:
2840: %\\ ! G-moveContents2!\\
2841: \S mC5:/ \>$ pc\geq 114\Land pc\neq 118~\implies \quad v_{\it mC}\neq\B done/$ \\
2842:
2843: %\\ ! G-moveContents3!\\
2844: \S mC6:/ \>$ pc\geq 114~\implies \quad i_{\it mC}<\T H/(\S index/).\T size/$ \\
2845:
2846:
2847: %\\ ! G-moveContents4 !\\
2848: \S mC7:/ \>$ pc=118~\implies \quad \T H/(\S index/).\T table/[i_{\it mC}]=\B done/$ \\
2849:
2850: %\\ ! G-moveContents5!\\
2851: \S mC8:/ \>$pc\geq 110 \Land k < \T H/(\S index/).\T size/\Land
2852: k\notin toBeMoved$\\
2853: \>$\implies \quad \T H/(\S index/).\T table/ [k]=\B done/$\\
2854:
2855: %\\ ! G-migrate7!\\
2856: \S mC9:/ \>$ pc \geq 110\Land \S index/=\T currInd/\Land toBeMoved=\emptyset $\\
2857: \>$\land\;\; k < \T H/(\S index/).\T size/$\\
2858: \> $\implies \quad \T H/(\S index/).\T table/[k]=\B done/$ \\
2859:
2860: %\\ ! G-moveContents6 \\!\\
2861: \S mC10:/ \>$ pc\geq 116\Land \S val/(v_{\it mC})\neq\B null/$\\
2862: \>$\land~ \T H/(\S index/).\T table/[i_{\it mC}]=\B done/$ \\
2863: \>$\implies \quad \T H/(i_{\it mig}).\T table/[\S key/(a,\T H/(i_{\it mig}).\T size/,0)]\neq \B null/$, \\
2864: \>where $a=\S ADR/(v_{\it mC})$ \\
2865:
2866:
2867: %\\ ! G-moveContents7!\\
2868: \S mC11:/ \>$ pc\geq 116 \Land\T H/(\S index/).\T table/[i_{\it mC}]\neq \B done/$ \\
2869: \>$\implies\quad \S val/(v_{\it mC})=\S val/(\T H/(\S index/).\T table/[i_{\it mC}])$\\
2870: \>$\Land~ \S oldp/(\T H/(\S index/).\T table/[i_{\it mC}])$\\
2871:
2872:
2873: %\\ ! G-moveContents7-1!\\
2874: \S mC12:/ \>$ pc\geq 116\Land \S index/=\T currInd/\Land\S val/(v_{\it mC})\neq\B null/$ \\
2875: \>$\implies \quad \S val/(v_{\it mC})=\S val/(\T Y/[i_{\it mC}])$
2876: \end{tab1}
2877:
2878:
2879: \medbreak Invariants concerning procedure \S moveElement/ (120\dots 126):
2880:
2881: \begin{tab1}
2882: %\\ ! G-moveContents8!\\
2883: \S mE1:/ \>$ pc\geq 120~\implies \quad \S val/(v_{\it mC})=v_{\it mE}$ \\
2884:
2885: %\\ ! G-moveElement1!\\
2886: \S mE2:/ \>$ pc \geq 120 ~\implies \quad v_{\it mE}\neq \B null/$\\
2887:
2888: %\\ ! G-moveElement2!\\
2889: \S mE3:/ \>$ pc \geq 120 ~\implies \quad to=\T H/(i_{\it mig})$\\
2890:
2891: %\\ ! G-moveElement11!\\
2892: \S mE4:/ \>$ pc \geq 121~\implies \quad a_{\it mE}=\S ADR/(v_{\it mC})$\\
2893:
2894: %\\ ! G-moveElement14!\\
2895: \S mE5:/ \>$ pc\geq 121~\implies \quad m_{\it mE}=to.\T size/$\\
2896:
2897: %\\ ! G-moveElement12!\\
2898: \S mE6:/ \>$ pc\in \{121,123\}~\implies \quad \neg b_{\it mE}$\\
2899:
2900: %\\ ! G-moveElement7!\\
2901: \S mE7:/ \>$ pc=123 ~\implies \quad k_{\it mE}=\S key/(a_{\it mE},to.\T size/,n_{\it mE})$\\
2902:
2903: %\\ ! G-moveElement13!\\
2904: \S mE8:/ \>$ pc\geq 123~\implies \quad k_{\it mE}<\T H/(i_{\it mig}).\T size/$\\
2905:
2906: %\\ ! G-moveElement6!\\
2907: \S mE9:/ \>$ pc=120 $\\
2908: \>$\land~ to.\T table/[\S key/(\S ADR/(v_{\it mE}),to.\T size/,0)]=\B null/$\\
2909: \>$\implies \quad \S index/=\T currInd/$\\
2910:
2911: %\\ ! G-moveElement3!\\
2912: \S mE10:/ \>$ pc \in \{121,123\}$\\
2913: \>$\land~ to.\T table/[\S key/(a_{\it mE},to.\T size/,n_{\it mE})]=\B null/$\\
2914: \>$\implies \quad \S index/=\T currInd/$\\
2915:
2916: %\\ ! G-moveElement4!\\
2917: \S mE11:/ \>$ pc \in \{121,123\}\Land pc.r=103 $\\
2918: \>$\land~ to.\T table/[\S key/(a_{\it mE},to.\T size/,n_{\it mE})]=\B null/$\\
2919: \>$\implies\quad \S index/.r\ne \T currInd/$\\
2920:
2921: %\\ ! G-moveElement8\\!\\
2922: \S mE12:/ \>$pc\in \{121,123\}\Land \T next/(\T currInd/)\neq 0 \Land to=\T H/(\T next/(\T currInd/))$\\
2923: \>$\implies \quad n_{\it mE}<\T H/(\T next/(\T currInd/)).\T size/$ \\
2924:
2925:
2926: %\\ ! G-moveElement10-1!\\
2927: \S mE13:/ \>$ pc \in \{123,125\}\Land w_{\it mE}\neq\B null/$\\
2928: \>$\implies\quad \S ADR/(w_{\it mE})=\S ADR/(to.\T table/[k_{\it mE}])$\\
2929: \>$~\Lor~ to.\T table/[k_{\it mE}]\in \{\B del/,\B done/\}$\\
2930:
2931: %\\ ! G-moveElement10!\\
2932: \S mE14:/ \>$ pc \geq 123 \Land w_{\it mE}\neq\B null/$\\
2933: \>$\implies \quad \T H/(i_{\it mig}).\T table/[k_{\it mE}]\neq\B null/$\\
2934:
2935: %\\ ! G-moveElement9!\\
2936: \S mE15:/ \>$ pc=117 \Land \S val/(v_{\it mC})\neq \B null/$\\
2937: \>$\lor~ pc\in \{121,123\}\Land n_{\it mE}>0$\\
2938: \>$\lor~ pc=125$\\
2939: \>$\implies \quad h.\T table/[\S key/(\S ADR/(v_{\it mC}),h.\T size/,0)]
2940: \neq\B null/$,\\
2941: \>where $h=\T H/(i_{\it mig})$\\
2942:
2943: %\\ ! G-moveElement5!\\
2944: \S mE16:/ \>$ pc \in \{121,123\}$\\
2945: \>$\lor~ ($\=$pc=125 \Land \neg b_{\it mE}$\\
2946: \>\>$\land~ (\S val/(w_{\it mE})=\B null/ \Lor a_{\it mE}\neq \S ADR/(w_{\it mE})))$\\
2947: \>$\implies \quad \forall m<n_{\it mE}:$\\
2948: \>\>~~$\neg \S Find/(to.\T table/[\S key/(a_{\it mE},to.\T size/,m)],a_{\it mE})$
2949: \end{tab1}
2950:
2951:
2952: \medbreak Invariants about the integer array \T prot/.
2953: \begin{tab1}
2954:
2955: %\\ ! G-prot!\\
2956: \S pr1:/ \> $ \T prot/[i] ~=~ $\=$ \sharp (\S prSet1/(i)) ~+~ \sharp (\S prSet2/(i)) ~+~ \sharp (\T currInd/=i)$\\
2957: \>\>$ +~ \sharp (\T next/(\T currInd/)=i)$ \\
2958:
2959: %\\ ! G-guard1-a!\\
2960: \S pr2:/ \>$ \T prot/[\T currInd/]>0$ \\
2961:
2962: %\\ ! G-guard1-b!\\
2963: \S pr3:/ \>$ pc \in [1,58]\Lor pc\geq 62 \Land pc\neq 65~\implies \quad \T prot/[\S index/]>0$ \\
2964:
2965: %\\ ! G-guard1-next!\\
2966: \S pr4:/ \>$ \T next/(\T currInd/)\neq 0~\implies \quad \T prot/[\T next/(\T currInd/)]>0$\\
2967:
2968: %\\ ! G-prot2!\\
2969: \S pr5:/ \>$ \T prot/[i]=0~\implies \quad \T Heap/(\T H/[i])=\bot$ \\
2970:
2971: %\\ ! G-prot3!\\
2972: \S pr6:/ \>$ \T prot/[i]\leq\sharp (\S prSet3/(i)) \Land \T busy/[i]=0~\implies \quad
2973: \T Heap/(\T H/[i])=\bot$ \\
2974:
2975: %\\ ! G-guard4!\\
2976: \S pr7:/ \>$ pc \in [67,72]~\implies \quad \T prot/[i_{\it rA}]>0$ \\
2977:
2978: %\\ ! G-guard6!\\
2979: \S pr8:/ \>$ pc\in [81,84]~\implies \quad \T prot/[i_{\it nT}]>0$\\
2980:
2981: %\\ ! G-guard5!\\
2982: \S pr9:/ \>$ pc\geq 97~\implies \quad \T prot/[i_{\it mig}]>0$ \\
2983:
2984: %\\ ! G-prot4!\\
2985: \S pr10:/ \>$ pc\in [81,82]~\implies \quad \T prot/[i_{\it nT}]=\sharp (prSet4(i_{\it nT}))+1$
2986: \end{tab1}
2987:
2988:
2989: \medbreak Invariants about the integer array \T busy/.
2990:
2991: \begin{tab1}
2992: %\\ ! G-busysize,G-busy!\\
2993: \S bu1:/ \> $ \T busy/[i] ~=~ $\=$\sharp (buSet1(i)) ~+~ \sharp (buSet2(i)) ~+~ \sharp (\T currInd/=i)$\\
2994: \>\>$ +~ \sharp (\T next/(\T currInd/)=i) $\\
2995:
2996: %\\ ! G-guard2-a!\\
2997: \S bu2:/ \>$ \T busy/[\T currInd/]>0$\\
2998:
2999: %\\ ! G-guard2-b!\\
3000: \S bu3:/ \>$ pc \in [1,58]$\\
3001: \>$\lor~ pc>65 \Land \neg(i_{\it rA}=\S index/ \Land pc \in [67,72])$\\
3002: \>$\implies \quad \T busy/[\S index/]>0$\\
3003:
3004: %\\ ! G-busy1-next!\\
3005: \S bu4:/ \>$ \T next/(\T currInd/)\neq 0~\implies \quad \T busy/[\T next/(\T currInd/)]>0$\\
3006:
3007: %\\ ! G-guard7!\\
3008: \S bu5:/ \>$ pc=81~\implies \quad \T busy/[i_{\it nT}]=0$\\
3009:
3010: %\\ ! G-guard3!\\
3011: \S bu6:/ \>$ pc\geq 100~\implies \quad \T busy/[i_{\it mig}]>0$
3012: \end{tab1}
3013:
3014:
3015: \medbreak Some other invariants we have postulated:
3016:
3017: \begin{tab1}
3018: %\\ ! G-ADR2!\\
3019: \S Ot1:/ \>$ \T X/(\B 0/)=\B null/$\\
3020: %\\ ! G-ADR1!\\
3021: \S Ot2:/ \>$ \T X/(a)\neq \B null/~\implies \quad \S ADR/(\T X/(a))=a$
3022: \end{tab1}
3023: The motivation of invariant (Ot1) is that we never store a value for
3024: the address 0.
3025: The motivation of invariant (Ot2) is that the address in the hash table
3026: is unique.
3027:
3028: \begin{tab1} %\\ ! G-R1!\\
3029: \S Ot3:/ \>$ return_{\it gA}=\{1, 10, 20, 30, 36, 46, 51\} \Land
3030: return_{\it rA}=\{0, 59, 77, 90\}$ \\
3031: \>$\land~ return_{\it ref}=\{10, 20, 30, 36, 46, 51\} \Land
3032: return_{\it nT}=\{30, 46\}$
3033: \end{tab1}
3034:
3035: \begin{tab1}
3036: %\\ ! G-pc!\\
3037: \S Ot4:/ \>$ pc\in \{$\=$0,~1,~5,~6,~7,~8,~10,~11,~13,~14,~15,~
3038: 16,~17,~18,~20,~$\\
3039: \>\>$21,~25,~26,~27,~28,~30,~31,~32,~33,~35,~36,~37,~41,~$\\
3040: \>\>$42,~43,~44,~46,~47,~48,~49,~50,~51,~52,~57,~59,~60,~$\\
3041: \>\>$61,~62,~63,~65,~67,~68,~69,~70,~71,~72,~77,~78,~81,~$\\
3042: \>\>$82,~83,~84,~90,~94,~95,~97,~98,~99,~100,~101,~102,~$\\
3043: \>\>$103,~104,~105,~110,~111,~114,~116,~117,~118,~120,~$\\
3044: \>\>$121,~123,~125,~126\}$
3045: \end{tab1}
3046:
3047: \section{Dependencies between invariants}
3048: Let us write ``$\phi\ \B from/\ \psi_1, \cdots, \psi_n $'' to denote
3049: that $\phi$ is proved to be an invariant using that $\psi_1$, \dots,
3050: $\psi_n $ hold.
3051: We write ``$\phi\ \Leftarrow\ \psi_1, \cdots, \psi_n $'' to denote
3052: that predicate $\phi$ is implied by the conjunction of $\psi_1$,
3053: \dots, $\psi_n $.
3054: We have verified the following ``\B from/'' and ``$\Leftarrow $''
3055: relations mechanically:
3056:
3057: \begin{tab}
3058: Co1 \B from/ fi10, Ot3, fi1\\
3059: Co2 \B from/ de5, Ot3, de6, del, de11\\
3060: Co3 \B from/ in5, Ot3, in6, in1, in11\\
3061: Cn1 \B from/ Cn6, Ot3\\
3062: Cn2 \B from/ Cn8, Ot3, del\\
3063: Cn3 \B from/ Cn10, Ot3, in1, in5\\
3064: Cn4 \B from/ Cn11, Ot3\\
3065: No1 $\Leftarrow $ No2\\
3066: No2 \B from/ nT1, He2, rA2, Ot3, Ha2, Ha1, rA1, rA14, rA3, nT14, rA4\\
3067: He1 \B from/ Ha1\\
3068: He2 \B from/ Ha3, rA5, Ha1, He1, rA2\\
3069: He3, He4 \B from/ Ot3, rA6, rA7, mi12, rA11, rA5\\
3070: He5 \B from/ He1\\
3071: He6 \B from/ rA8, Ha3, mi8, nT2, rA5\\
3072: Ha1 \B from/ true\\
3073: Ha2 \B from/ Ha1\\
3074: Ha3 \B from/ Ha2, Ha1, He2, He1\\
3075: Ha4 $\Leftarrow $ Ha3, He3, He4\\
3076: Cn5 \B from/ Cn6, Ot3 \\
3077: Cn6 \B from/ Cn5, Ot3\\
3078: Cn7 \B from/ Cn8, Ot3, del\\
3079: Cn8 \B from/ Cn7, Ot3 \\
3080: Cn9 \B from/ Cn10, Ot3, in1, in5\\
3081: Cn10 \B from/ Cn9, Ot3, in5\\
3082: Cn11 \B from/ Cn11, Ot3\\
3083: Cu1 \B from/ Ot3, Ha4, rA6, rA7, nT13, nT12, Ha2, He3, He4, rA11, nT9, nT10,\\
3084: \> mi13, rA5\\
3085: Cu2 $\Leftarrow $ Cu6, cu7, Cu3, He3, He4\\
3086: Cu3 \B from/ rA6, rA7, nT13, nT12, mi5, mi4, Ne8, rA5\\
3087: Cu4 \= \B from/ del, in1, as1, rA6, rA7, Ha2, nT13, nT12, Ne9, Cu9, Cu10, de7, \\
3088: \> in7, as5, He3, He4, mi5, mi4, Ot3, Ha4, de3, mi9, mi10, de5, rA5\\
3089: Cu6 \= \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, Ha3, in3, as3, Ne23, mi5, mE6,\\
3090: \> mE7, mE10, mE3, Ne3, mi1, mi4, rA5\\
3091: Cu7 \= \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, Ha3, in3, as3, in5, mi5, mE6, \\
3092: \> mE7, mE10, mE3, Ne3, mi4, de7, in7, as5, Ne22, mi9, mi10, rA5, He3, \\
3093: \> mi12, mi1, Cu9, de1 in1, as1\\
3094: Cu8 \= \B from/ Cu8, Ha2, nT9, nT10, rA6, rA7, mi5, mi4, mC2, mC5, He3,\\
3095: \> He4, Cu1, Ha4, mC6, mi16, rA5\\
3096: Cu9\=, Cu10 \B from/ rA6, rA7, nT13, nT12, Ha2, He3, He4, Cu1, Ha4, de3, in3,\\
3097: \> as3, mE3, mi9, mi10, mE10, mE7, rA5\\
3098: Cu11\=, Cu12 \B from/ Cu9, Cu10, Cu13, Cu14, del, in1, as1, rA6, rA7, Ha2, nT13,\\
3099: \> nT12, He3, He4, Cu1, Ha4, in3, as3, mi14, mi15, de3, in10, as8, mi12, \\
3100: \> Ot2, fi5, de8, in8, as6, Cu15, de11, in11, rA5\\
3101: Cu13\=, Cu14 \B from/ He3, He4, Ot2, del, in1, as1, Ot1, rA6, rA7, nT13, nT12, \\
3102: \> Ha2, Cu9, Cu10, Cu1, Ha4, de3, in3, as3, Cu11, Cu12, in10, as8, fi5, de8, \\
3103: \> in8, as6, Cu15, mi17, mi18, mi12, mi4, de11, rA5\\
3104: Cu15\=\ \B from/ He3, He4, rA6, rA7, nT13, nT12, Ha2, Cu1, Ha4, del, in1, as1,\\
3105: \> de3, in3, as3, fi5, de8, in8, as6, mi12, mi19, mi4, Ot2, Cu9, Cu10, Cu11, \\
3106: \> Cu12, Cu13, Cu14, rA5 \\
3107: Cu16 $\Leftarrow $ Cu13, Cu14, Cu15, He3, He4, Ot1\\
3108: Ne1 \B from/ nT9, nT10, mi7\\
3109: Ne2 \B from/ Ne5, nT3, mi8, nT9, nT10\\
3110: Ne3 \B from/ Ne1, nT9, nT10, mi8\\
3111: Ne4 \B from/ Ne1, nT9, nT10\\
3112: Ne5 \B from/ Ot3, nT9, nT10, mi5\\
3113: Ne6 $\Leftarrow $ Ne10, Ne24, He6, He3, He4, Cu4\\
3114: Ne7 \B from/ Ha3, rA6, rA7, rA8, nT13, nT12, nT11, He3, He4, mi8, nT7, \\
3115: \> Ne5, Ha2, He6, rA5\\
3116: Ne8 \B from/ Ha3, rA8, nT11, mi8, nT6, Ne5, rA5\\
3117: Ne9 \B from/ Ha3, Ha2, Ne3, Ne5, de3, as3, rA8, rA6, rA7, nT8, nT11, mC2, \\
3118: \> nT4, mi8, rA5\\
3119: Ne9a \B from/ Ha3, Ne3, rA5, de3, rA8, nT4, mi8\\
3120: Ne10 \B from/ Ha3, Ha2, de3, rA8, nT11, Ne3, He6, mi8, nT8, mC2, nT2, Ne5, \\
3121: \> rA5\\
3122: Ne11 \B from/ Ha3, Ha2, He6, nT2, nT8, rA8, nT11, mi8, Ne3, mC2, rA5\\
3123: Ne12\=, Ne13 \B from/ Ha3, Ha2, Cu8, He6, He3, He4, Cu1, de3, in3, as3, rA8, rA6, \\
3124: \> rA7, nT11, nT13, nT12, mi12, mi16, mi5, mi4, de7, in7, as5, Ot2, del,in1, \\
3125: \> as1, Cu9, Cu10, Cu13, Cu14, Cu15, as9, fi5, de8, in8, as6, mC2, Ne3, Ot1, \\
3126: \> Ne14, Ne20, mE16, mE7, mE4, mE1, mE12, mE2, Ne15, Ne16, Ne17,\\
3127: \> Ne18, mi20, de11, in11, rA5 \\
3128: Ne14\=\ \B from/ Ha3, Ha2, He6, He3, He4, nT2, nT8, de3, in3, as3, rA8, nT11,\\
3129: \> Ot2, del, in1, as1, Cu9, Cu10, mi8, Ne3, mC2, mE7, mE16, mE1, mE4, \\
3130: \> mE12, Ne17, Ne18, Cu1, rA5\\
3131: Ne15\=, Ne16 \B from/ Ha3, Ha2, Cu8, He6, He3, He4, Cu1, de3, in3, as3, rA8, rA6, \\
3132: \> rA7, nT11, nT13, nT12, mi12, mi16, mi5, mi4, de7, in7, as5, Ot2, del, in1, \\
3133: \> as1, Cu9, Cu10, Cu13, Cu14, Cu15, as9, fi5, de8, in8, as6, mC2, Ne3, Ot1, \\
3134: \> Ne19, Ne20, Ne12, Ne13, mE16, mE7, mE4, mE1, mE12, mE10, mE2, \\
3135: \> in11, de11, rA5\\
3136: Ne17\=, Ne18 \B from/ Ha3, Ha2, mi8, He6, He3, He4, Cu1, nT2, de3, in3, as3, rA8,\\
3137: \> rA6, rA7, nT11, nT13, nT12, de7, in7, as5, Ot2, del, in1, as1, Cu9, Cu10, \\
3138: \> nT8, mE2, fi5, de8, in8, as6, mC2, Ne3, mC11, mC6, mC12, mE7, mE10,\\
3139: \> mE1, Cu8, Cu15, Cu13, Cu14, Cu11, Cu12, as8, de11, rA5\\
3140: Ne19\=\ \B from/ Ha3, Ha2, He6, nT2, nT8, de3, in3, as3, rA8, nT11, mi8, Ne3, \\
3141: \> mE7, Ne14, mE16, Ot1, mE1, mE4, mE12, Ne17, Ne18, rA5\\
3142: Ne20\=\ \B from/ Ha3, Ha2, Cu8, He6, He3, He4, Cu1, Ha4, de3, in3, as3, rA8, rA6,\\
3143: \> rA7, nT11, nT13, nT12, mi12, mi16, mi5, mi4, Ne1, de7, in7, as5, del, in1,\\
3144: \> as1, Cu9, Cu10, Cu13, Cu14, Cu15, as9, fi5, de8, in8, as6, mC2, Ne3, Ot1,\\
3145: \> mi20, in11, rA5\\
3146: Ne22\=\ \B from/ Ot3, rA8, Ha2, nT11, Ha3, de3, in3, as3, mi5, mi4, Ne3, nT18,\\
3147: \> mE3, mi8, mE10, mE7, mE6, Ne5, nT5, nT2, rA5, nT8, nT12, mC2, mE2\\
3148: Ne23 $\Leftarrow $ Cu6, cu7, Ne6, Ne7, He3, He4, Ne22, He6\\
3149: Ne24 $\Leftarrow $ Ne27, He6 \\
3150: Ne25 $\Leftarrow $ Ne19, Ne17, Ne18, He6 \\
3151: Ne26 $\Leftarrow $ Ne17, Ne18, He6\\
3152: Ne27 $\Leftarrow $ Cu16, Ne25, Ne26, Ne17, Ne18, He6 \\
3153: fi1, del, in1, as1 \B from/ \\
3154: fi2 \B from/ fi2, Ot3 \\
3155: fi3 \B from/ fi4, Ot3, rA6, rA7, Ha2, rA5\\
3156: fi4 \B from/ Ot3, rA6, rA7, nT13, nT12 \\
3157: fi5, de8, in8, as6 $\Leftarrow $ Cu2, de10, in10, as8, fi8, He3, He4\\
3158: fi6 \= \B from/ Ot3, fi1, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, Cu9, \\
3159: \> Cu10, He3, He4, Cu1, Ha4, fi4, in3, as3, rA5\\
3160: fi7 \= \B from/ fi8, fi6, fi2, Ot3, fi1, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, \\
3161: \> mi10, Cu9, Cu10, He3, He4, Cu1, Ha4, fi4, in3, as3, rA5\\
3162: fi8 \= \B from/ fi4, fi7, fi2, Ot3, fi1, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9,\\
3163: \> mi10, Cu9, Cu10, He3, He4, Cu1, Ha4, in3, as3, rA5\\
3164: fi9 \= $\Leftarrow $ Cu1, Ha4, Cu9, Cu10, Cu11, Cu12, fi8, fi3, fi4, fi5, de8, in8, \\
3165: \> as6, He3, He4\\
3166: fi10 \B from/ fi9, Ot3\\
3167: fi11\=, de12, in12, as10 \B from/ Ot3, nT9, nT10, mi9, mi10, Cu8, fi4, de3, in3, \\
3168: \> as3, fi3, de2, in2, as2\\
3169: de2 \B from/ de3, Ot3, rA6, rA7, Ha2, rA5\\
3170: de3 \B from/ Ot3, rA6, rA7, nT13, nT12 \\
3171: de4, in4, as4 \B from/ Ot3\\
3172: de5 \B from/ Ot3 \\
3173: de6 \B from/ Ot3, de1, de11 \\
3174: de7, in7, as5 $\Leftarrow $ de3, in3, as3, Cu1, Ha4, de13, in13, as11\\
3175: de9 \= \B from/ Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, \\
3176: \> Cu9, Cu10, de3, de7, in7, as5, rA5\\
3177: de10\=\ \B from/ de3, de9, Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, \\
3178: \> mi10, Cu9, Cu10, de7, in7, as5, He3, He4, rA5\\
3179: de11 $\Leftarrow $ de10, de2, de3, He3, He4, Cu1, Ha4, Cu9, Cu10, Cu11, Cu12, fi5, \\
3180: \> de8, in8, as6 \\
3181: de13, in13, as11 $\Leftarrow $ Ax2, de2, de3, de4, in2, in3, in4, as2, as3, as4\\
3182: in2 \B from/ in3, Ot3, rA6, rA7, Ha2, rA5\\
3183: in3 \B from/ Ot3, rA6, rA7, nT13, nT12\\
3184: in5 \B from/ Ot3\\
3185: in6 \B from/ Ot3, in1, in11\\
3186: in9 \= \B from/ Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, Cu9,\\
3187: \> Cu10, He3, He4, in3, de7, in7, as5, rA5\\
3188: in10\=\ \B from/ in9, fi2, Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, \\
3189: \> Cu9, Cu10, He3, He4, in3, de7, in7, as5, rA5\\
3190: in11 $\Leftarrow $ in10, in2, in3, Cu1, Ha4, Cu9, Cu10, Cu11, Cu12, fi5, de8, in8, as6 \\
3191: as2 \B from/ as3, He3, He4, Ot3, rA6, rA7, Ha2, rA5\\
3192: as3 \B from/ Ot3, rA6, rA7, nT13, nT12 \\
3193: as7 \= \B from/ Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, Cu9, \\
3194: \> Cu10, as3, de7, in7, as5, rA5\\
3195: as8 \= \B from/ as7, Ot3, del, in1, as1, rA6, rA7, Ha2, nT13, nT12, mi9, mi10, Cu9, \\
3196: \> Cu10, He3, He4, as3, de7, in7, as5, rA5\\
3197: as9 $\Leftarrow $ as8, as2, as3, He3, He4, Cu1, Ha4, Cu9, Cu10, Cu11, Cu12, fi5, de8,\\
3198: \> in8, as6 \\
3199: rA1 \B from/ Ha2\\
3200: rA2 \B from/ Ot3\\
3201: rA3 \B from/ Ot3, rA9, He2, He1, rA2, rA13 \\
3202: rA4 \B from/ Ot3, nT14\\
3203: rA5 \B from/ Ot3, rA1, rA2, Ha3, He2\\
3204: rA6\=, rA7 \B from/ Ot3, nT13, nT12, nT14, rA11, mi4, bu2, bu3, Ha3, mi6, Ha2,\\
3205: \> He3, He4, He2, rA2\\
3206: rA8 \B from/ Ot3, bu4, nT14, mi6, Ne2, mi5\\
3207: rA9 \B from/ Ot3, Ha2, nT14, He1, He2\\
3208: rA10 \B from/ Ot3\\
3209: rA11 \B from/ Ot3, nT13, nT12, mi2\\
3210: rA12 \B from/ Ot3, nT9, nT10\\
3211: rA13 \B from/ Ot3, rA5\\
3212: rA14 \B from/ Ot3, rA4, He1, rA2\\
3213: nT1 \B from/ Ot3, pr5, Ha3, nT14, nT16, Ha2\\
3214: nT2 \B from/ Ot3, nT14, Ha3, rA5\\
3215: nT3 \B from/ Ot3, nT9, nT10\\
3216: nT4 \B from/ Ot3, Ha3, de3, nT13, nT12, nT15, rA5\\
3217: nT5 \B from/ Ot3, Ha3, in3, as3, nT13, nT12, nT15, nT18, mE3, mi4, rA5\\
3218: nT6 \B from/ Ot3, nT13, nT12, nT14, Ha3, rA5\\
3219: nT7 \B from/ Ot3, nT13, nT12, nT15, rA6, rA7, Ha2, mi9, mi10, nT14, Ha3, \\
3220: \> nT16, rA5\\
3221: nT8 \= \B from/ Ot3, de3, in3, as3, nT13, nT12, nT15, nT18, mE3, mi4, Ha3, mC2,\\
3222: \> nT16, nT2, Ha2, rA5\\
3223: nT9, nT10 \B from/ Ot3, pr2, pr3, nT18 \\
3224: nT11 \B from/ Ot3, pr4, nT16, mi8\\
3225: nT13, nT12 $\Leftarrow $ nT9, nT10, Ha3, He3, He4\\
3226: nT14 \B from/ Ot3, nT9, nT10, nT18, nT16, pr7\\
3227: nT15 $\Leftarrow $ nT14, Ha3, nT2\\
3228: nT16 \B from/ Ot3, pr8\\
3229: nT17 \B from/ Ot3, mi5, pr4, nT11, mi10\\
3230: nT18 \B from/ Ot3, pr9, mi5, nT11\\
3231: mi1 \B from/ Ot3, mi9, mi10, mi10\\
3232: mi2 \B from/ Ot3, Ne4\\
3233: mi3 \B from/ Ot3, fi11, de12, in12, as10, nT9, nT10, Ne5\\
3234: mi4 \B from/ Ot3, mi9, mi10, mi3\\
3235: mi5 \B from/ Ot3, nT9, nT10, Ne5, mi10, mi4\\
3236: mi6 \B from/ Ot3, mi5, bu6, rA8, mi9, mi10, bu4, mi4\\
3237: mi7 \B from/ Ot3, mi2, mi7, mi4, nT18, Ne2, mi10, nT17, mi3\\
3238: mi8 \B from/ Ot3, mi10, Ne2, mi3\\
3239: mi9,\=\ mi10 \B from/ Ot3, He3, He4, nT9, nT10, nT18, Ne3, Ha3, mi3, nT17, \\
3240: \> mi10, He2, mi4, mi12, mi6, He6 \\
3241: mi11 \B from/ Ot3, nT18, mi9, mi6, mi6\\
3242: mi12 \B from/ Ot3, rA8, nT2, He6, mi9, mi5, mi3, Ha3, mi4, rA5\\
3243: mi12 \B from/ Ot3, mi12, nT18, mi6, Ha3, mi4, rA5\\
3244: mi13 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, He3, He4, mi9, mi10, mC9, rA5\\
3245: mi14\=, mi15 $\Leftarrow $ Ne12, Ne13, mi5, Cu15, mi13, Ot2, He3, He4, Ne17, Ne18,\\
3246: \> Cu8, He6, He5, mi4, Ot1\\
3247: mi16 $\Leftarrow $ Ne11, mi5, mi4 \\
3248: mi17, mi18 $\Leftarrow $ Ne15, Ne16, mi5, Cu15, mi13, Ot2, He3, He4, Ne17, Ne18, \\
3249: \> Cu8, He6, He5, mi4\\
3250: mi19 $\Leftarrow $ Ne20, mi5, Cu15, mi13, Ot2, He3, He4\\
3251: mi20 \=\ \B from/ Ha3, Ha2, Cu8, He6, He3, He4, Cu1, Ha4, de3, in3, as3, rA8, \\
3252: \> rA6, rA7, nT11, nT13, nT12, mi5, mi4, de7, in7, as5, Ot2, del, in1, \\
3253: \> as1, Cu9, Cu10, Cu13, Cu14, Cu15, as9, fi5, de8, in8, as6, mC6, Ne3,\\
3254: \> Ot3, mC11, mi13, mi9, mi10, mC2, mE3, mE10, mE7, mC12, mE1, \\
3255: \> mE13, Ne17, Ne18, mE2, mE4, Ot1, mE6, Ne10, in11, rA5\\
3256: mC1 \B from/ Ot3, mi6, mi11, nT18 \\
3257: mC2 \B from/ Ot3, rA6, rA7, nT13, nT12, mC2\\
3258: mC3 \B from/ Ot3, mC3, nT13, nT12, rA6, rA7, Ha2, rA5\\
3259: mC4 \B from/ Ot3, mC4, mC2, mC3, He3, He4, rA6, rA7, Ha2, rA5\\
3260: mC5 \B from/ Ot3 \\
3261: mC6 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, mC2, rA5\\
3262: mC7 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, mC2, rA5\\
3263: mC8 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, He3, He4, mC7, rA5\\
3264: mC9 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, He3, He4, mi9, mi10, He5, \\
3265: \> mC7, mC8, rA5\\
3266: mC10\=\ \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, mC2, del, in1, as1, mi6,\\
3267: \> Ha3, mi4, nT18, mE15, mC11, mi5, rA5\\
3268: mC11 \B from/ Ot3, rA6, rA7, Ha2, nT13, nT12, mC2, rA5\\
3269: mC12 \B from/ Ot3, rA6, rA7, mC2, mC11, Cu9, Cu10, de7, in7, as5, mi9,\\
3270: \> mC6 \\
3271: mE1 \B from/ Ot3 \\
3272: mE2 \B from/ Ot3 \\
3273: mE3 \B from/ mC1, Ot3, mi6, nT18 \\
3274: mE4 \B from/ Ot3, mE1\\
3275: mE5 \B from/ Ot3, mE3, Ha3, mi6, mi4, nT18, Ha2, rA5\\
3276: mE6 \B from/ Ot3 \\
3277: mE7 \B from/ Ot3, Ha2, Ha3, mi6, mi4, mE3, rA5\\
3278: mE8 \B from/ Ot3, Ha3, mi6, mi4, nT18, Ha2, mE3, rA5\\
3279: mE9 \= \B from/ Cu1, Ha4, Ot3, Ha2, Ha3, mi6, mi4, mE3, mC2, mC10, mE1, \\
3280: \> mC1, del, in1, as1, mi13, mi12, mC6, mE2, rA5\\
3281: mE10 \B from/ del, in1, as1, mE3, mi6, Ot3, Ha2, Ha3, mi4, mE11, mE9,\\
3282: \> mE7, rA5\\
3283: mE11\=\ $\Leftarrow $ mE10, mi13, mE16, mi16, mi5, mE3, Ne12, Ne13, mC12, mE2,\\
3284: \> mE1, mE4, mC6, mE12, mi12, Cu13, Cu14, He3, He4, mi4\\
3285: mE12 $\Leftarrow $ Ne23, Ne22, mE16, He6, Ne8\\
3286: mE13 \B from/ Ot3, Ha2, mE14, del, in1, as1, Ha3, mi6, mi4, mE3, rA5\\
3287: mE14 \B from/ Ot3, Ha2, del, in1, as1, Ha3, mi6, mi4, nT18, mE3, mE2, rA5\\
3288: mE15\=\ \B from/ Ot3, mE1, Ha2, del, in1, as1, Ha3, mi6, mi4, nT18, mE3, mE2,\\
3289: \> mE7, mE14, mE4, rA5\\
3290: mE16\=\ \B from/ Ha3, Ha2, mE3, del, in1, as1, mi6, mE2, mE4, mE1, mE7, mi4,\\
3291: \> Ot3, mE14, mE13, rA5\\
3292: pr1 \B from/ Ot3, rA11, rA10, nT9, nT10, Ne5, mi2, mi4, mi8, mi5\\
3293: pr2, pr3 \B from/ pr1, Ot3, rA11, mi1 \\
3294: pr4 $\Leftarrow $ pr1\\
3295: pr5 $\Leftarrow $ pr6, pr1, bu1\\
3296: pr6 \B from/ Ot3, Ha2, nT9, nT10, nT14, nT16, He2, rA2, pr1, bu1, pr10, \\
3297: \> rA9, He1, rA4\\
3298: pr7, pr8, pr9 $\Leftarrow $ pr1, mi4\\
3299: pr10 \B from/ Ot3, pr1, nT9, nT10, nT14, nT17\\
3300: bu1 \B from/ Ot3, rA11, rA10, nT9, nT10, Ne5, mi2, mi8, mi5, bu5\\
3301: bu2, bu3 $\Leftarrow $ bu1, Ot3, rA10\\
3302: bu4 $\Leftarrow $ bu1\\
3303: bu5 \B from/ Ot3, nT9, nT10, nT16, nT18, pr1, bu1\\
3304: bu6 $\Leftarrow $ bu1, mi4\\
3305: Ot1 \B from/ del, in1, as1\\
3306: Ot2 \B from/ del, in1, as1\\
3307: Ot3 \B from/ true\\
3308: Ot4 \B from/ Ot3\\
3309: \end{tab}
3310:
3311: \begin{thebibliography}{10}
3312:
3313: \bibitem{ARJ97}
3314: J.H. Anderson, S.~Ramamurthy, and K.~Jeffay.
3315: \newblock Real-time computing with lock-free shared objects.
3316: \newblock {\em ACM Trans. Comput. Syst.}, 15(2):134--165, 1997.
3317:
3318: \bibitem{ABD90}
3319: H.~Attiya, A.~Bar-Noy, D.~Dolev, D.~Peleg, and R.~Reischuk.
3320: \newblock Renaming in an asynchronous environment.
3321: \newblock {\em Journal of the ACM}, 37:524--548, 1990.
3322:
3323: \bibitem{BD89}
3324: A.~Bar-Noy and D.~Dolev.
3325: \newblock Shared-memory vs.\ message-passing in an asynchronous distributed
3326: environment.
3327: \newblock In {\em Proc.\ 8th ACM Symp.\ on principles of distributed
3328: computing}, pages 307--318, 1989.
3329:
3330: \bibitem{Bar93}
3331: G.~Barnes.
3332: \newblock A method for implementing lock-free shared-data structures.
3333: \newblock In {\em Proceedings of the fifth annual ACM symposium on Parallel
3334: algorithms and architectures}, pages 261--270. ACM Press, 1993.
3335:
3336: \bibitem{FCB00}
3337: F.~Cassez, C.~Jard, B.~Rozoy, and M.~Dermot.
3338: \newblock Modeling and verification of parallel processes, 2000.
3339: \newblock 4th Summer School, MOVEP 2000, Nantes, France.
3340:
3341: \bibitem{HesMv}
3342: H.~Gao, J.F. Groote, and W.H. Hesselink.
3343: \newblock {PVS} verification.
3344: \newblock \\\verb!http://www.cs.rug.nl/~wim/mechver/hashtable!, 2003.
3345:
3346: \bibitem{Jan00}
3347: J.F. Groote, W.H. Hesselink, S.~Mauw, and R.~Vermeulen.
3348: \newblock An algorithm for the asynchronous write-all problem based on process
3349: collision.
3350: \newblock {\em Distr. Comput.}, 14:75--81, 2001.
3351:
3352: \bibitem{Har92}
3353: S.P. Harbison.
3354: \newblock {\em Modula-3}.
3355: \newblock Prentice Hall, New Yersey, 1992.
3356:
3357: \bibitem{Her91}
3358: M.~Herlihy.
3359: \newblock Wait--free synchronization.
3360: \newblock {\em ACM Trans. Program. Lang. Syst.}, 13:124--149, 1991.
3361:
3362: \bibitem{Her93}
3363: M.~Herlihy.
3364: \newblock A methodology for implementing highly concurrent data objects.
3365: \newblock {\em ACM Trans. Program. Lang. Syst.}, 15:745--770, 1993.
3366:
3367: \bibitem{HeW90}
3368: M.~Herlihy and J.~Wing.
3369: \newblock Linearizability: a correctness condition for concurrent objects.
3370: \newblock {\em ACM Trans. Program. Lang. Syst.}, 12:463--492, 1990.
3371:
3372: \bibitem{HeM92}
3373: M.P. Herlihy and J.E.B. Moss.
3374: \newblock Lock-free garbage collection for multiprocessors.
3375: \newblock {\em IEEE Transactions on Parallel and Distributed Systems},
3376: 3:304--311, 1992.
3377:
3378: \bibitem{H95}
3379: W.H. Hesselink.
3380: \newblock Wait--free linearization with a mechanical proof.
3381: \newblock {\em Distr. Comput.}, 9:21--36, 1995.
3382:
3383: \bibitem{H96}
3384: W.H. Hesselink.
3385: \newblock Bounded delay for a free address.
3386: \newblock {\em Acta Inf.}, 33:233--254, 1996.
3387:
3388: \bibitem{HG99}
3389: W.H. Hesselink and J.F. Groote.
3390: \newblock Wait-free concurrent memory management by {C}reate, and {R}ead until
3391: {D}eletion ({CaRuD}).
3392: \newblock {\em Distr. Comput.}, 14:31--39, 2001.
3393:
3394: \bibitem{KS97}
3395: P.C. Kanellakis and A.A. Shvartsman.
3396: \newblock {\em Fault-tolerant parallel computation}.
3397: \newblock Kluwer Academic Publishers, Dordrecht, 1997.
3398:
3399: \bibitem{Knuth3}
3400: D.E. Knuth.
3401: \newblock {\em The Art of Computer Programming. Part 3, Sorting and searching}.
3402: \newblock Addison-Wesley, 1973.
3403:
3404: \bibitem{LaMa94}
3405: A.~LaMarca.
3406: \newblock A performance evaluation of lock-free synchronization protocols.
3407: \newblock In {\em Proceedings of the thirteenth annual ACM symposium on
3408: Principles of distributed computing}, pages 130--140. ACM Press, 1994.
3409:
3410: \bibitem{Lam94}
3411: L.~Lamport.
3412: \newblock The temporal logic of actions.
3413: \newblock {\em ACM Trans. Program. Lang. Syst.}, 16:872--923, 1994.
3414:
3415: \bibitem{Lyn96}
3416: N.A. Lynch.
3417: \newblock {\em Distributed Algorithms}.
3418: \newblock Morgan Kaufman, San Francisco, 1996.
3419:
3420: \bibitem{ZA92}
3421: Z.~Manna and A.~Pnueli.
3422: \newblock {\em The Temporal Logic of Reactive and Concurrent Systems:
3423: Specification}.
3424: \newblock Springer, New York, 1992.
3425:
3426: \bibitem{Mic02}
3427: M.M. Michael.
3428: \newblock High performance dynamic lock-free hash tables and list-based sets.
3429: \newblock In {\em Proceedings of the fourteenth annual ACM symposium on
3430: Parallel algorithms and architectures}, pages 73--82. ACM Press, 2002.
3431:
3432: \bibitem{OSR01}
3433: S.~Owre, N.~Shankar, J.~M. Rushby, and D.~W.~J. Stringer-Calvert.
3434: \newblock {\em PVS Version 2.4, System Guide, Prover Guide, PVS Language
3435: Reference}, 2001.
3436: \newblock \verb!http://pvs.csl.sri.com!
3437:
3438: \bibitem{RaG02}
3439: R.~Rajwar and J.R. Goodman.
3440: \newblock Transactional lock-free execution of lock-based programs.
3441: \newblock In {\em Tenth international conference on architectural support for
3442: programming languages and operating systems on Proceedings of the 10th
3443: international conference on architectural support for programming languages
3444: and operating systems (ASPLOS-X)}, pages 5--17. ACM Press, 2002.
3445:
3446: \bibitem{ShS03}
3447: O.~Shalev and N.~Shavit.
3448: \newblock Split-ordered lists: lock-free extensible hash tables.
3449: \newblock In {\em Proceedings of the twenty-second annual symposium on
3450: Principles of distributed computing}, pages 102--111. ACM Press, 2003.
3451:
3452: \bibitem{SuT04}
3453: H.~Sundell and P.~Tsigas.
3454: \newblock Scalable and lock-free concurrent dictionaries.
3455: \newblock In {\em Proceedings of the 2004 ACM symposium on Applied computing},
3456: pages 1438--1445. ACM Press, 2004.
3457:
3458: \bibitem{Valois92}
3459: J.D. Valois.
3460: \newblock Implementing lock-free queues.
3461: \newblock In {\em Proceedings of the seventh international conference on
3462: Parallel and Distributed Computing Systems}, pages 64--69, 1994.
3463:
3464: \bibitem{Valois94}
3465: J.D. Valois.
3466: \newblock Lock-free linked lists using compare-and-swap.
3467: \newblock In {\em Proceedings of the fourteenth annual ACM symposium on
3468: Principles of distributed computing}, pages 214--222. ACM Press, 1995.
3469: \newblock See also J.D.~Valois. ERRATA. Lock-free linked lists using
3470: compare-and-swap. Unpublished manuscript, 1995.
3471:
3472: \bibitem{Wir}
3473: N.~Wirth.
3474: \newblock {\em Algorithms $+$ Data Structures $=$ Programs}.
3475: \newblock Prentice Hall, 1976.
3476:
3477: \end{thebibliography}
3478:
3479: \end{document}
3480: