File: channels.tex

package info (click to toggle)
rabbitmq-java-client 5.0.0-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 2,752 kB
  • sloc: java: 24,907; xml: 1,245; python: 697; makefile: 47; sh: 25
file content (245 lines) | stat: -rw-r--r-- 9,851 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
\documentclass[a4paper,twoside,12pt]{article}
\usepackage{zed-cm}
\usepackage{graphicx}
\markboth{Draft}{Version 0.1}
\pagestyle{myheadings}

\begin{document}
\parskip 2 pt
\parindent 10 pt

\title{Channeling Work}
\author{Steve Powell \and Rob Harrop}
\maketitle
% The following three commands ensure the title page is stamped as
% confidential without a page number. Page numbering is started at the
% table of contents.
\thispagestyle{myheadings}
\pagenumbering{roman}
\setcounter{page}{1}

%=============================================================================
\abstract{A short specification arising from Rob's investigation into serving messages on a collection of channels with a limited number of threads, preserving ordering constraints.}

% Cntrl-Cmd-M -- \emph{}
% Cntrl-Cmd-Z -- \zed{}
% Cntrl-Cmd-X -- \axdef{}
% Cntrl-Cmd-S -- \schema{}
% Cntrl-Cmd-C -- \texttt{}


% Type checking hacks
\newcommand{\true}{true}
\newcommand{\false}{false}
\renewcommand{\emptyset}{\varnothing}

%=====================================================================
\clearpage
\tableofcontents

\clearpage
\pagenumbering{arabic}

%=====================================================================
\section{Introduction}
The primitives in this description are $Channel$s and items of $Work$.  It is assumed that work is a message transfer or acknowledgement of some kind. It is not important.  What is important is that a series of items of $Work$ needs to be done for a $Channel$ and we cannot allow two items of work to be processed for the same $Channel$ at the same time. So we introduce the primitive sets:
\begin{zed}
[ Channel, Work ]
\end{zed}
and with these we can describe the general state.

%=====================================================================
\section{The general state of things}
The basic state of the system is a collection of $Channel$s with a sequence of items of work associated with each:
\begin{schema}{Pool}
pool : Channel \pfun \seq Work
\end{schema}

The $pool$ of known channels ($\dom pool$) is partitioned into those which are $dormant$, those $ready$ for work to be done, and those which are currently being processed ($inprogress$).

We define a convenience schema for each partition.  This is to name them for use in explicitly stating preservation later.

The $dormant$ ones have no work (but we cannot impose this constraint without the $pool$ -- we do it later):
\begin{schema}{Dormant}
dormant : \power Channel
\end{schema}
the $ready$ ones are ordered:
\begin{schema}{Ready}
ready : \iseq Channel
\end{schema}
and the rest are `in progress':
\begin{schema}{InProgress}
inprogress : \power Channel
\end{schema}

\subsection{The state of the union}
We can now assemble the entire system state as follows:
\begin{schema}{State}
Pool \\
Dormant \\
Ready \\
InProgress
\where
\langle dormant, \ran ready, inprogress \rangle \partition \dom pool
\also
\forall c : dormant @ pool ~ c = \langle \rangle
\end{schema}
where we make explicit that these channel collections partition those known (in $\dom pool$), and can also impose the constraint that the $dormant$ channels have no work.

%
\section{Work delivery}
In general, as it comes in, work is added to the sequence of items associated with a channel in the $pool$. However, the precise change of state depends upon which partition the channel is in at the time.

We therefore define three `deliver work' state transitions; one for each partition. In each case different partitions change as a result.  They share the same signature, and underlying pool change, however:
\begin{schema}{DeliverWorkCommon}
\Delta State \\
w? : Work \\
c? : Channel
\where
c? \in \dom pool \\
pool ' = pool \oplus \{ c? \mapsto pool ~ c? \cat \langle w? \rangle \}
\end{schema}
each of them changes the $State$, and takes an item of work and a channel as input. In every case, the work is added to the $pool$.

When the channel is dormant it moves into the ready queue (and the `in progress' partition remains unchanged):
\begin{schema}{DeliverDormant}
DeliverWorkCommon \\
\Xi InProgress
\where
c? \in dormant \\
dormant ' = dormant \setminus \{c?\} \\
ready' = ready \cat \langle c? \rangle
\end{schema}
(Note that in this case the resulting sequence of work is simply $\langle w? \rangle$.) 

When the channel is already `in progress' the partitions stay unchanged: 
\begin{schema}{DeliverInProgress}
DeliverWorkCommon \\
\Xi InProgress \\
\Xi Dormant \\
\Xi Ready
\where
c? \in inprogress
\end{schema}
(and we need say nothing more).

When the channel is ready (in the $ready$ queue) the partitions stay unchanged as well:
\begin{schema}{DeliverReady}
DeliverWorkCommon \\
\Xi InProgress \\
\Xi Dormant \\
\Xi Ready
\where
c? \in \ran ready
\end{schema}
(and we need say nothing more).

Since the preconditions of the $Deliver$ schemas are disjoint, we may combine them without introducing any further non-determinism:
\begin{zed}
DeliverWork\defs DeliverDormant \lor DeliverInProgress \lor DeliverReady
\end{zed}

\section{Start work}
When there is time (and available computing resources) we can start some work.  We consider only doing one piece of work at a time, though it is easy to consider `batching' work items together.

The operation that starts it picks a piece of work to do, and gives the work and channel as outputs.  The dormant channels are unaffected, and the channel moves from ready to `in progress':
\begin{schema}{StartWork}
\Delta State \\
\Xi Dormant \\
c! : Channel \\
w! : Work
\where
ready \neq \langle \rangle \\
\langle c! \rangle \cat ready' = ready \\
inprogress' = inprogress \cup \{ c! \} \\
\langle w! \rangle \cat pool' ~ c! = pool ~ c! \\
\{ c! \} \ndres pool' = \{ c! \} \ndres pool
\end{schema}
where the channel simply gets `taken' from the front of the ready queue; the work gets `taken' from the front of the work queue for the channel; the channel gets put in the `in progress' partition and no other channels are affected.

Notice that here, although apparently there might be no work left, the channel is not put into the $dormant$ partition until the current work is completed.  It is quite in order for non-$dormant$ channels to have no work \emph{pro tem}, though we expect such a channel to be placed in $dormant$ eventually.

\section{Our work is done}
After the work is completed the channel can be taken out of `in progress'. Of course, there might already be more work to do (or not) and these cases are distinguished.

We define a `partial operation' to identify the essence of work completion:
\begin{schema}{EndWorkCommon}
\Delta State \\
\Xi Pool \\
c? : Channel
\where
c? \in inprogress \\
inprogress' = inprogress \setminus \{c?\} \\
pool' = pool
\end{schema}
This only happens for channels in $inprogress$ and this channel is always removed from there. None of the work queues change as a result of this transition. 

If there is no more work to do, the channel becomes dormant (and the ready queue remains unchanged):
\begin{schema}{EndWorkNoMoreToDo}
EndWorkCommon \\
\Xi Ready
\where
pool ~ c? = \langle \rangle \\
dormant' = dormant \cup \{ c? \}
\end{schema}
(We could have deduced the dormant relation -- and, as it happens, the pool constraint -- from the core work and the fact that the ready queue does not change.)

If there \emph{is} more work to do, the channel becomes $ready$ (though not so ready as some \emph{al}ready):
\begin{schema}{EndWorkMoreToDo}
EndWorkCommon \\
\Xi Dormant
\where
pool ~ c? \neq \langle \rangle \\
ready ' = ready \cat \langle c? \rangle
\end{schema}
The channel is placed on the `end' of the ready queue.

Should we be so inclined, since the preconditions of the two $EndWork$ schemas are disjoint, we can unambiguously combine them:
\begin{zed}
EndWork \defs EndWorkMoreToDo \lor EndWorkNoMoreToDo
\end{zed}

\section{To begin with...}
After constructing this description, we note that there is no channel creation nor deletion described, and that the initial state is not given.  This is an ideal opportunity to record our intentions in these areas.  We can even document the rules for pieces of work left over when a channel `crashes', in some way, or if the item of work `fails'.

We limit this brief note to talk about the initial state.

In the absence of channel creation or deletion, we will provide the set of channels initially:
\begin{schema}{InitialState}
State' \\
cs? : \power Channel
\where
dormant' = cs? \\
pool' = \{ c : cs? @ c \mapsto  \langle \rangle \}
\end{schema}
The set of channels is precisely the dormant set initially, and the pool records no work at all.
The $\partition$ constraint on $State$ ensures that the rest of the initial state is determined:
\begin{zed}
InitialState \vdash ready' = \langle \rangle \land inprogress' = \emptyset 
\end{zed}

\section{Summary}
Essentially, this simple arrangement makes sure that pieces of work for the same channel never overtake each other, even if there are free servers ready to do more work at all times.

\begin{figure}[h]
\centering
\includegraphics*[scale=0.7]{worktransition.pdf}
\caption{Channel state movements}
\label{fig:statediag}
\end{figure}
The operations defined here can be diagrammed (see figure \ref{fig:statediag}) as transitions between three `states' of a channel, corresponding to the partitions of the $\dom pool$ collection.

This picture was constructed \emph{after} the specification was written, and seems bleedin' obvious. 'Twas ever thus.

This document fully type-checks (with Fuzz).

\subsection{...footnote}
\begin{figure}[h]
\centering
\includegraphics*[width=1.5\linewidth,angle=90]{whiteboard.JPG}
\caption{board marks}
\label{fig:whiteboard}
\end{figure}
Figure \ref{fig:whiteboard} is a picture of the ``whiteboard'' resulting from the original discussion and from which this document was created.

\end{document}