• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SpiNNakerManchester / JavaSpiNNaker / 13502930948

24 Feb 2025 04:31PM UTC coverage: 38.515% (-0.01%) from 38.525%
13502930948

push

github

rowleya
Client and server side of Fast Data Write

653 of 981 new or added lines in 8 files covered. (66.56%)

4 existing lines in 2 files now uncovered.

9190 of 23861 relevant lines covered (38.51%)

1.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/SpiNNaker-comms/src/main/java/uk/ac/manchester/spinnaker/alloc/client/SpallocClient.java
1
/*
2
 * Copyright (c) 2021 The University of Manchester
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package uk.ac.manchester.spinnaker.alloc.client;
17

18
import static java.lang.String.join;
19
import static java.nio.charset.StandardCharsets.UTF_8;
20
import static org.apache.commons.io.IOUtils.readLines;
21

22
import java.io.FileNotFoundException;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.nio.ByteBuffer;
26
import java.util.List;
27
import java.util.stream.Stream;
28

29
import javax.validation.Valid;
30
import javax.validation.constraints.NotNull;
31

32
import com.google.errorprone.annotations.MustBeClosed;
33

34
import uk.ac.manchester.spinnaker.machine.ChipLocation;
35
import uk.ac.manchester.spinnaker.machine.CoreLocation;
36
import uk.ac.manchester.spinnaker.machine.HasChipLocation;
37
import uk.ac.manchester.spinnaker.machine.MemoryLocation;
38
import uk.ac.manchester.spinnaker.machine.board.PhysicalCoords;
39
import uk.ac.manchester.spinnaker.machine.board.TriadCoords;
40
import uk.ac.manchester.spinnaker.machine.tags.IPTag;
41
import uk.ac.manchester.spinnaker.messages.model.Version;
42
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
43
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;
44
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
45

46
/**
47
 * An API for talking to the Spalloc service.
48
 *
49
 * @see SpallocClientFactory
50
 * @author Donal Fellows
51
 */
52
public interface SpallocClient {
53
    /**
54
     * Get the server version ID.
55
     *
56
     * @return A version ID.
57
     * @throws IOException
58
     *             If things go wrong.
59
     */
60
    Version getVersion() throws IOException;
61

62
    /**
63
     * Get a list of all Spalloc machines.
64
     *
65
     * @return The list of machines.
66
     * @throws IOException
67
     *             If things go wrong.
68
     */
69
    List<Machine> listMachines() throws IOException;
70

71
    /**
72
     * List the existing non-terminated jobs.
73
     *
74
     * @param waitForChange
75
     *            If {@code true}, will wait until the list of jobs may have
76
     *            changed. (Best-effort only; waiting time is bounded at 30
77
     *            seconds.)
78
     * @return A list of jobs.
79
     * @throws IOException
80
     *             If things go wrong.
81
     */
82
    List<Job> listJobs(boolean waitForChange) throws IOException;
83

84
    /**
85
     * List the jobs, including the deleted ones.
86
     * <p>
87
     * <strong>NB:</strong> Care should be taken; this may produce a lot of
88
     * output.
89
     *
90
     * @param waitForChange
91
     *            If {@code true}, will wait until the list of jobs may have
92
     *            changed. (Best-effort only; waiting time is bounded at 30
93
     *            seconds.)
94
     * @return A stream of jobs.
95
     * @throws IOException
96
     *             If things go wrong.
97
     */
98
    Stream<Job> listJobsWithDeleted(boolean waitForChange) throws IOException;
99

100
    /**
101
     * List the existing non-terminated jobs.
102
     *
103
     * @return A list of jobs.
104
     * @throws IOException
105
     *             If things go wrong.
106
     */
107
    default List<Job> listJobs() throws IOException {
NEW
108
        return listJobs(false);
×
109
    }
110

111
    /**
112
     * List the jobs, including the deleted ones.
113
     * <p>
114
     * <strong>NB:</strong> Care should be taken; this may produce a lot of
115
     * output.
116
     *
117
     * @return A stream of jobs.
118
     * @throws IOException
119
     *             If things go wrong.
120
     */
121
    default Stream<Job> listJobsWithDeleted() throws IOException {
NEW
122
        return listJobsWithDeleted(false);
×
123
    }
124

125
    /**
126
     * Create a job.
127
     *
128
     * @param createInstructions
129
     *            Describes the job to create.
130
     * @return A handle to the created job.
131
     * @throws IOException
132
     *             If job creation fails.
133
     */
134
    Job createJob(CreateJob createInstructions) throws IOException;
135

136
    /** The services offered relating to a Spalloc machine. */
137
    interface Machine {
138
        /**
139
         * The machine's name. Never empty, never {@code null}.
140
         *
141
         * @return The name of the machine.
142
         */
143
        String getName();
144

145
        /**
146
         * The tags of the machine. If this includes "{@code default}", this is
147
         * the machine that jobs will usually go to.
148
         *
149
         * @return The tags of the machine.
150
         */
151
        List<String> getTags();
152

153
        /**
154
         * The width of the machine.
155
         *
156
         * @return The width of the machine, in triads.
157
         */
158
        int getWidth();
159

160
        /**
161
         * The height of the machine.
162
         *
163
         * @return The height of the machine, in triads.
164
         */
165
        int getHeight();
166

167
        /**
168
         * The number of live boards.
169
         *
170
         * @return The (estimated) number of live boards in the machine.
171
         */
172
        int getLiveBoardCount();
173

174
        /**
175
         * What boards in the machine are dead?
176
         *
177
         * @return The dead boards of the machine.
178
         */
179
        List<BoardCoords> getDeadBoards();
180

181
        /**
182
         * What links in the machine are dead? Only links where both boards are
183
         * alive.
184
         *
185
         * @return The dead links of the machine.
186
         */
187
        List<DeadLink> getDeadLinks();
188

189
        /**
190
         * Wait (for up to 30 seconds) until the state of the machine might have
191
         * changed.
192
         *
193
         * @throws IOException
194
         *             If communication with the server fails
195
         */
196
        void waitForChange() throws IOException;
197

198
        /**
199
         * Given logical triad coordinates, return more info about a board.
200
         *
201
         * @param coords
202
         *            Triad coordinates
203
         * @return Board information
204
         * @throws FileNotFoundException
205
         *             If the board doesn't exist.
206
         * @throws IOException
207
         *             If communication with the server fails
208
         */
209
        WhereIs getBoard(@NotNull @Valid TriadCoords coords)
210
                throws FileNotFoundException, IOException;
211

212
        /**
213
         * Given physical coordinates, return more info about a board.
214
         *
215
         * @param coords
216
         *            Physical coordinates.
217
         * @return Board information
218
         * @throws FileNotFoundException
219
         *             If the board doesn't exist.
220
         * @throws IOException
221
         *             If communication with the server fails
222
         */
223
        WhereIs getBoard(@NotNull @Valid PhysicalCoords coords)
224
                throws FileNotFoundException, IOException;
225

226
        /**
227
         * Given a <em>global</em> chip location, return more info about the
228
         * board that contains it.
229
         *
230
         * @param chip
231
         *            The chip location
232
         * @return Board information
233
         * @throws FileNotFoundException
234
         *             If the board doesn't exist.
235
         * @throws IOException
236
         *             If communication with the server fails
237
         */
238
        WhereIs getBoard(@NotNull @Valid HasChipLocation chip)
239
                throws FileNotFoundException, IOException;
240

241
        /**
242
         * Given an IP address, return more info about a board.
243
         *
244
         * @param address
245
         *            Board IP address
246
         * @return Board information
247
         * @throws FileNotFoundException
248
         *             If the board doesn't exist.
249
         * @throws IOException
250
         *             If communication with the server fails
251
         */
252
        WhereIs getBoard(@IPAddress String address)
253
                throws FileNotFoundException, IOException;
254
    }
255

256
    /**
257
     * The services offered relating to a Spalloc job. Jobs run on
258
     * {@linkplain Machine machines}, and have boards allocated to them while
259
     * they do so. Those boards (which will be connected) are a fundamental
260
     * resource that allows SpiNNaker programs to be run.
261
     */
262
    interface Job {
263
        /**
264
         * Get a description of a job. Includes the state of the job.
265
         *
266
         * @param waitForChange
267
         *            If {@code true}, will wait until the jobs may have
268
         *            changed. (Best-effort only; waiting time is bounded at 30
269
         *            seconds.)
270
         * @return The job description &amp; state. Check the state to see
271
         *         whether the job has had resources allocated yet.
272
         * @throws IOException
273
         *             If communication fails.
274
         */
275
        JobDescription describe(boolean waitForChange) throws IOException;
276

277
        /**
278
         * Get a description of a job. Includes the state of the job.
279
         *
280
         * @return The job description &amp; state. Check the state to see
281
         *         whether the job has had resources allocated yet.
282
         * @throws IOException
283
         *             If communication fails.
284
         */
285
        default JobDescription describe() throws IOException {
NEW
286
            return describe(false);
×
287
        }
288

289
        /**
290
         * Must be periodically called to prevent the service watchdog from
291
         * culling the job.
292
         *
293
         * @throws IOException
294
         *             If communication fails.
295
         */
296
        void keepalive() throws IOException;
297

298
        /**
299
         * Mark a job as deleted.
300
         *
301
         * @param reason
302
         *            Why the job is to be deleted.
303
         * @throws IOException
304
         *             If communication fails.
305
         */
306
        void delete(String reason) throws IOException;
307

308
        /**
309
         * Get a description of what's been allocated to the job.
310
         *
311
         * @return a description of the allocated resources
312
         * @throws IOException
313
         *             If communication fails, the resources have not yet been
314
         *             allocated, or the job is deleted.
315
         */
316
        AllocatedMachine machine() throws IOException;
317

318
        /**
319
         * Get whether the boards of the machine are all switched on.
320
         *
321
         * @return {@code true} iff the boards are all on.
322
         * @throws IOException
323
         *             If communication fails, the resources have not yet been
324
         *             allocated, or the job is deleted.
325
         */
326
        boolean getPower() throws IOException;
327

328
        /**
329
         * Set the power state of the boards of the machine. Note that actually
330
         * changing the power state of the boards may take some time.
331
         *
332
         * @param switchOn
333
         *            {@code true} to switch the boards on, {@code false} to
334
         *            switch them off.
335
         * @return {@code true} iff the boards are all on.
336
         * @throws IOException
337
         *             If communication fails, the resources have not yet been
338
         *             allocated, or the job is deleted.
339
         */
340
        boolean setPower(boolean switchOn) throws IOException;
341

342
        /**
343
         * Given the location of a chip within an allocation, return more info
344
         * about a board.
345
         *
346
         * @param chip
347
         *            Chip location (relative to the root of the allocation).
348
         * @return Board information
349
         * @throws FileNotFoundException
350
         *             If the board doesn't exist or no boards are allocated to
351
         *             the job currently.
352
         * @throws IOException
353
         *             If communication fails or the job is deleted.
354
         */
355
        WhereIs whereIs(@NotNull @Valid HasChipLocation chip)
356
                throws FileNotFoundException, IOException;
357

358
        /**
359
         * Create a proxied transceiver for talking to the boards of the job.
360
         * The transceiver will be configured so that it can talk to all the
361
         * boards of the job and nothing else; the BMP(s) will <em>not</em> be
362
         * accessible by this transceiver.
363
         *
364
         * @return The transceiver. It is the caller's responsibility to close
365
         *         this transceiver at the right time.
366
         * @throws IOException
367
         *             If communication fails or the job is deleted.
368
         * @throws InterruptedException
369
         *             If interrupted waiting for the connection to be set up.
370
         * @throws SpinnmanException
371
         *             If transceiver construction fails.
372
         */
373
        @MustBeClosed
374
        TransceiverInterface getTransceiver()
375
                throws IOException, InterruptedException, SpinnmanException;
376

377
        /**
378
         * Wait until the job's boards are powered on or the job is destroyed.
379
         *
380
         * @throws IOException
381
         *             If communication fails.
382
         */
383
        default void waitForPower() throws IOException {
NEW
384
            var state = describe().getState();
×
NEW
385
            while (state == State.QUEUED || state == State.POWER) {
×
NEW
386
                state = describe(true).getState();
×
387
            }
NEW
388
        }
×
389

390
        /**
391
         * Write memory directly using the Spalloc API.
392
         *
393
         * @param chip The chip to write to
394
         * @param baseAddress The base address to write to
395
         * @param data The data to write
396
         * @throws IOException
397
         *             If communications fail.
398
         */
399
        void writeMemory(HasChipLocation chip, MemoryLocation baseAddress,
400
                ByteBuffer data) throws IOException;
401

402
        /**
403
         * Read memory directly using the Spalloc API.
404
         *
405
         * @param chip The chip to read from
406
         * @param baseAddress The base address to read from
407
         * @param length The number of bytes to read
408
         * @return The data read
409
         * @throws IOException
410
         *             If communications fail.
411
         */
412
        ByteBuffer readMemory(HasChipLocation chip, MemoryLocation baseAddress,
413
                int length) throws IOException;
414

415
        /**
416
         * Fast write data directly with a job.  Assumes it has been set up.
417
         *
418
         * @param gathererCore The core to use on the Ethernet chip.
419
         * @param ethernetChip The Ethernet chip to use to write data.
420
         * @param ethernetAddress The IP address of the Ethernet chip.
421
         * @param iptag The tag ID to use for reading responses.
422
         * @param chip The chip to write to.
423
         * @param baseAddress The base address to write to.
424
         * @param data The data to write.
425
         *
426
         * @throws IOException
427
         *             If communications fail.
428
         */
429
        void fastWriteData(CoreLocation gathererCore,
430
            ChipLocation ethernetChip, String ethernetAddress,
431
            IPTag iptag, HasChipLocation chip, MemoryLocation baseAddress,
432
            ByteBuffer data) throws IOException;
433
    }
434

435
    /**
436
     * Exception caused by the server sending an error.
437
     */
438
    class SpallocException extends RuntimeException {
439
        private static final long serialVersionUID = -1363689283367574333L;
440

441
        /** The HTTP response code that triggered the exception. */
442
        private final int responseCode;
443

444
        /**
445
         * Create an instance.
446
         *
447
         * @param message
448
         *            The message body of the error.
449
         * @param responseCode
450
         *            The HTTP response code that triggered the exception.
451
         */
452
        public SpallocException(String message, int responseCode) {
NEW
453
            super(message);
×
NEW
454
            this.responseCode = responseCode;
×
NEW
455
        }
×
456

457
        SpallocException(InputStream stream, int responseCode)
458
                throws IOException {
NEW
459
            super(consume(stream));
×
NEW
460
            this.responseCode = responseCode;
×
NEW
461
        }
×
462

463
        private static String consume(InputStream stream) throws IOException {
464
            try {
NEW
465
                return join("\n", readLines(stream, UTF_8));
×
466
            } finally {
NEW
467
                stream.close();
×
468
            }
469
        }
470

471
        /**
472
         * @return The HTTP response code that triggered the exception.
473
         */
474
        public int getResponseCode() {
NEW
475
            return responseCode;
×
476
        }
477
    }
478
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc