• 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

50.82
/SpiNNaker-allocserv/src/main/java/uk/ac/manchester/spinnaker/alloc/allocator/SpallocAPI.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.allocator;
17

18
import static java.util.Objects.isNull;
19
import static java.util.Objects.nonNull;
20
import static java.util.Objects.requireNonNull;
21
import static uk.ac.manchester.spinnaker.alloc.Constants.TRIAD_DEPTH;
22
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.IS_NMPI_EXEC;
23
import static uk.ac.manchester.spinnaker.alloc.security.SecurityConfig.MAY_SEE_JOB_DETAILS;
24

25
import java.io.IOException;
26
import java.time.Duration;
27
import java.time.Instant;
28
import java.util.Collection;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.Objects;
32
import java.util.Optional;
33
import java.util.Set;
34

35
import javax.validation.Valid;
36
import javax.validation.constraints.AssertTrue;
37
import javax.validation.constraints.NotNull;
38
import javax.validation.constraints.Positive;
39
import javax.validation.constraints.PositiveOrZero;
40

41
import org.springframework.security.access.prepost.PostFilter;
42
import org.springframework.security.access.prepost.PreAuthorize;
43

44
import com.google.errorprone.annotations.Keep;
45

46
import uk.ac.manchester.spinnaker.alloc.compat.V1CompatService;
47
import uk.ac.manchester.spinnaker.alloc.model.BoardCoords;
48
import uk.ac.manchester.spinnaker.alloc.model.ConnectionInfo;
49
import uk.ac.manchester.spinnaker.alloc.model.DownLink;
50
import uk.ac.manchester.spinnaker.alloc.model.JobDescription;
51
import uk.ac.manchester.spinnaker.alloc.model.JobListEntryRecord;
52
import uk.ac.manchester.spinnaker.alloc.model.JobState;
53
import uk.ac.manchester.spinnaker.alloc.model.MachineDescription;
54
import uk.ac.manchester.spinnaker.alloc.model.MachineListEntryRecord;
55
import uk.ac.manchester.spinnaker.alloc.model.PowerState;
56
import uk.ac.manchester.spinnaker.alloc.proxy.ProxyCore;
57
import uk.ac.manchester.spinnaker.alloc.security.Permit;
58
import uk.ac.manchester.spinnaker.alloc.web.IssueReportRequest;
59
import uk.ac.manchester.spinnaker.machine.ChipLocation;
60
import uk.ac.manchester.spinnaker.machine.HasChipLocation;
61
import uk.ac.manchester.spinnaker.machine.HasCoreLocation;
62
import uk.ac.manchester.spinnaker.machine.ValidX;
63
import uk.ac.manchester.spinnaker.machine.ValidY;
64
import uk.ac.manchester.spinnaker.machine.board.BMPCoords;
65
import uk.ac.manchester.spinnaker.machine.board.PhysicalCoords;
66
import uk.ac.manchester.spinnaker.machine.board.TriadCoords;
67
import uk.ac.manchester.spinnaker.machine.board.ValidTriadHeight;
68
import uk.ac.manchester.spinnaker.machine.board.ValidTriadWidth;
69
import uk.ac.manchester.spinnaker.spalloc.messages.BoardCoordinates;
70
import uk.ac.manchester.spinnaker.spalloc.messages.BoardPhysicalCoordinates;
71
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
72
import uk.ac.manchester.spinnaker.transceiver.TransceiverInterface;
73
import uk.ac.manchester.spinnaker.utils.UsedInJavadocOnly;
74
import uk.ac.manchester.spinnaker.utils.validation.IPAddress;
75

76
/**
77
 * The API of the core service that interacts with the database.
78
 *
79
 * @author Donal Fellows
80
 */
81
public interface SpallocAPI {
82
    /**
83
     * List the machines.
84
     *
85
     * @param allowOutOfService
86
     *            Whether to include machines marked as out of service.
87
     * @return A mapping from names to machines (which are live objects).
88
     */
89
    Map<String, Machine> getMachines(boolean allowOutOfService);
90

91
    /**
92
     * List the machines.
93
     *
94
     * @param allowOutOfService
95
     *            Whether to include machines marked as out of service.
96
     * @return A description of all the machines.
97
     */
98
    List<MachineListEntryRecord> listMachines(boolean allowOutOfService);
99

100
    /**
101
     * Get a specific machine.
102
     *
103
     * @param name
104
     *            The name of the machine to get.
105
     * @param allowOutOfService
106
     *            Whether to include machines marked as out of service.
107
     * @return A machine, on which more operations can be done.
108
     */
109
    Optional<Machine> getMachine(@NotNull String name,
110
            boolean allowOutOfService);
111

112
    /**
113
     * Get info about a specific machine.
114
     *
115
     * @param machine
116
     *            The name of the machine to get.
117
     * @param allowOutOfService
118
     *            Whether to include machines marked as out of service.
119
     * @param permit
120
     *            Encodes what the caller may do.
121
     * @return A machine description model.
122
     */
123
    Optional<MachineDescription> getMachineInfo(@NotNull String machine,
124
            boolean allowOutOfService, Permit permit);
125

126
    /**
127
     * List the jobs.
128
     *
129
     * @param deleted
130
     *            Whether to include deleted jobs in the list.
131
     * @param limit
132
     *            Maximum number of jobs in the returned list. Used for paging.
133
     * @param start
134
     *            How many jobs to skip past. Used for paging.
135
     * @return A list of jobs.
136
     */
137
    Jobs getJobs(boolean deleted, int limit, int start);
138

139
    /**
140
     * List the active jobs.
141
     *
142
     * @param permit
143
     *            Encodes what the caller may do.
144
     * @return A description of all the active jobs.
145
     */
146
    List<JobListEntryRecord> listJobs(Permit permit);
147

148
    /**
149
     * Get a specific job. Only owners or admins can see full job details or
150
     * manipulate the job.
151
     *
152
     * @param permit
153
     *            Encodes what the caller may do.
154
     * @param id
155
     *            The identifier of the job.
156
     * @return A job object on which more operations can be done, or empty if
157
     *         the job isn't there or isn't available to you.
158
     */
159
    @PostFilter(MAY_SEE_JOB_DETAILS)
160
    Optional<Job> getJob(Permit permit, int id);
161

162
    /**
163
     * Get a specific job. Only owners or admins can see full job details or
164
     * manipulate the job.
165
     *
166
     * @param permit
167
     *            Encodes what the caller may do.
168
     * @param id
169
     *            The identifier of the job.
170
     * @return A job description, or empty if the job isn't there (or isn't
171
     *         available to you).
172
     */
173
    @PostFilter(MAY_SEE_JOB_DETAILS)
174
    Optional<JobDescription> getJobInfo(Permit permit, int id);
175

176
    /**
177
     * Create a job for a user that is only in one group.
178
     * Note that jobs <em>cannot</em> be created on machines that
179
     * are out of service, but marking a machine as out of service does not stop
180
     * the jobs that are already running on it.
181
     *
182
     * @param owner
183
     *            Who is making this job.
184
     * @param descriptor
185
     *            What sort of allocation is desired?
186
     * @param machineName
187
     *            The name of the machine the user wants to allocate on, or
188
     *            {@code null} if they want to select by tags.
189
     * @param tags
190
     *            The tags of the machine the user wants to allocate on, or
191
     *            {@code null} if they want to select by name.
192
     * @param keepaliveInterval
193
     *            The maximum interval between keepalive requests or the job
194
     *            becomes eligible for automated deletion.
195
     * @param originalRequest
196
     *            The serialized original request, which will be stored in the
197
     *            database for later retrieval.
198
     * @return The job created.
199
     * @throws IllegalArgumentException if the job could not be created.
200
     */
201
    Job createJob(@NotNull String owner,
202
            @Valid CreateDescriptor descriptor, String machineName,
203
            List<String> tags, Duration keepaliveInterval,
204
            byte[] originalRequest) throws IllegalArgumentException;
205

206
    /**
207
     * Create a job for a user in a specific local group.
208
     * Note that jobs <em>cannot</em> be created on machines that
209
     * are out of service, but marking a machine as out of service does not stop
210
     * the jobs that are already running on it.
211
     *
212
     * @param owner
213
     *            Who is making this job.
214
     * @param group
215
     *            What group is associated with this job for accounting
216
     *            purposes.
217
     * @param descriptor
218
     *            What sort of allocation is desired?
219
     * @param machineName
220
     *            The name of the machine the user wants to allocate on, or
221
     *            {@code null} if they want to select by tags.
222
     * @param tags
223
     *            The tags of the machine the user wants to allocate on, or
224
     *            {@code null} if they want to select by name.
225
     * @param keepaliveInterval
226
     *            The maximum interval between keepalive requests or the job
227
     *            becomes eligible for automated deletion.
228
     * @param originalRequest
229
     *            The serialized original request, which will be stored in the
230
     *            database for later retrieval.
231
     * @return The job created.
232
     * @throws IllegalArgumentException if the job could not be created.
233
     */
234
    Job createJobInGroup(@NotNull String owner, @NotNull String group,
235
            @Valid CreateDescriptor descriptor, String machineName,
236
            List<String> tags, Duration keepaliveInterval,
237
            byte[] originalRequest) throws IllegalArgumentException;
238

239
    /**
240
     * Create a job for interactive use in an NMPI Collab Session.
241
     * Note that jobs <em>cannot</em> be created on machines that
242
     * are out of service, but marking a machine as out of service does not stop
243
     * the jobs that are already running on it.
244
     *
245
     * @param owner
246
     *            Who is making this job.
247
     * @param nmpiCollab
248
     *            The NMPI Collab to manage a session in, and from which the
249
     *            quota will be used.
250
     * @param descriptor
251
     *            What sort of allocation is desired?
252
     * @param machineName
253
     *            The name of the machine the user wants to allocate on, or
254
     *            {@code null} if they want to select by tags.
255
     * @param tags
256
     *            The tags of the machine the user wants to allocate on, or
257
     *            {@code null} if they want to select by name.
258
     * @param keepaliveInterval
259
     *            The maximum interval between keepalive requests or the job
260
     *            becomes eligible for automated deletion.
261
     * @param originalRequest
262
     *            The serialized original request, which will be stored in the
263
     *            database for later retrieval.
264
     * @return The job created.
265
     * @throws IllegalArgumentException if the job could not be created.
266
     */
267
    Job createJobInCollabSession(@NotNull String owner,
268
            @NotNull String nmpiCollab,
269
            @Valid CreateDescriptor descriptor, String machineName,
270
            List<String> tags, Duration keepaliveInterval,
271
            byte[] originalRequest) throws IllegalArgumentException;
272

273
    /**
274
     * Create a job for interactive use in an NMPI Collab Session.
275
     * Note that jobs <em>cannot</em> be created on machines that
276
     * are out of service, but marking a machine as out of service does not stop
277
     * the jobs that are already running on it.
278
     *
279
     * @param owner
280
     *            Who is making this job.
281
     * @param nmpiJobId
282
     *            The NMPI Job to allocate the quota used to.  The collab of
283
     *            the Job will be used for internal accounting purposes.
284
     * @param descriptor
285
     *            What sort of allocation is desired?
286
     * @param machineName
287
     *            The name of the machine the user wants to allocate on, or
288
     *            {@code null} if they want to select by tags.
289
     * @param tags
290
     *            The tags of the machine the user wants to allocate on, or
291
     *            {@code null} if they want to select by name.
292
     * @param keepaliveInterval
293
     *            The maximum interval between keepalive requests or the job
294
     *            becomes eligible for automated deletion.
295
     * @param originalRequest
296
     *            The serialized original request, which will be stored in the
297
     *            database for later retrieval.
298
     * @return The job created.
299
     * @throws IllegalArgumentException if the job could not be created.
300
     */
301
    @PreAuthorize(IS_NMPI_EXEC)
302
    Job createJobForNMPIJob(@NotNull String owner, int nmpiJobId,
303
            @Valid CreateDescriptor descriptor,        String machineName,
304
            List<String> tags, Duration keepaliveInterval,
305
            byte[] originalRequest) throws IllegalArgumentException;
306

307
    /** Purge the cache of what boards are down. */
308
    void purgeDownCache();
309

310
    /**
311
     * Tells the service that there may be a problem with a board at a
312
     * particular address.
313
     *
314
     * @param address
315
     *            The IP address of the board. Note that we haven't yet
316
     *            identified which machine has the board.
317
     * @param coreLocation
318
     *            Where on the board is the problem. If the problem is at the
319
     *            core level, it's a {@link HasCoreLocation}. If the problem is
320
     *            at the board level, this is {@code null}.
321
     * @param description
322
     *            Optional problem description. May be {@code null}.
323
     * @param permit
324
     *            Who is making the request.
325
     */
326
    @UsedInJavadocOnly(HasCoreLocation.class)
327
    void reportProblem(@IPAddress String address, HasChipLocation coreLocation,
328
            String description, Permit permit);
329

330
    /**
331
     * Describes what sort of request to create a job this is.
332
     *
333
     * @see CreateNumBoards
334
     * @see CreateDimensions
335
     * @see CreateDimensionsAt
336
     * @see CreateBoard
337
     */
338
    abstract class CreateDescriptor {
339
        /**
340
         * The maximum number of dead boards tolerated in the allocation.
341
         * Ignored when asking for a single board.
342
         */
343
        @PositiveOrZero(message = "maxDeadBoards must not be negative")
344
        public final int maxDead;
345

346
        /**
347
         * Only known subclasses permitted.
348
         *
349
         * @param maxDeadBoards
350
         *            The maximum number of dead boards. {@code null} is
351
         *            equivalent to 0.
352
         */
353
        private CreateDescriptor(Integer maxDeadBoards) {
3✔
354
            this.maxDead = isNull(maxDeadBoards) ? 0 : maxDeadBoards;
3✔
355
        }
3✔
356

357
        /**
358
         * Apply a visitor to this descriptor.
359
         *
360
         * @param <T>
361
         *            The type of the result of the visiting.
362
         * @param visitor
363
         *            The visitor to apply.
364
         * @return The result computed by the visitor.
365
         */
366
        public final <T> T visit(CreateVisitor<T> visitor) {
367
            return doVisit(requireNonNull(visitor));
3✔
368
        }
369

370
        /**
371
         * Get the area. The area is the number of boards required.
372
         *
373
         * @return The number of boards requested by the job.
374
         */
375
        public abstract int getArea();
376

377
        abstract <T> T doVisit(CreateVisitor<T> visitor);
378
    }
379

380
    /**
381
     * A request for a number of boards.
382
     */
383
    final class CreateNumBoards extends CreateDescriptor {
384
        /** The number of boards requested. */
385
        @Positive(message = "number of boards to request must be positive")
386
        public final int numBoards;
387

388
        /**
389
         * Request a count of boards. The service <em>may</em> over-allocate.
390
         *
391
         * @param numBoards
392
         *            The number of boards desired.
393
         * @param maxDeadBoards
394
         *            The number of dead boards that can be tolerated within
395
         *            that.
396
         */
397
        public CreateNumBoards(int numBoards, Integer maxDeadBoards) {
398
            super(maxDeadBoards);
3✔
399
            this.numBoards = numBoards;
3✔
400
        }
3✔
401

402
        @Override
403
        <T> T doVisit(CreateVisitor<T> visitor) {
404
            return visitor.numBoards(this);
3✔
405
        }
406

407
        @Override
408
        public int getArea() {
409
            return numBoards;
3✔
410
        }
411
    }
412

413
    /**
414
     * A request for a rectangle of boards. This is expressed in boards for
415
     * reasons relating to the legacy API.
416
     *
417
     * @see V1CompatService
418
     */
419
    @UsedInJavadocOnly(V1CompatService.class)
420
    final class CreateDimensions extends CreateDescriptor {
421
        /** Width requested, in triads. */
422
        @ValidTriadWidth
423
        public final int width;
424

425
        /** Height requested, in triads. */
426
        @ValidTriadHeight
427
        public final int height;
428

429
        /**
430
         * Request a rectangle of boards. The service <em>may</em>
431
         * over-allocate.
432
         *
433
         * @param width
434
         *            The width of rectangle to request, in triads.
435
         * @param height
436
         *            The height of rectangle to request, in triads.
437
         * @param maxDeadBoards
438
         *            The number of dead boards that can be tolerated in that
439
         *            rectangle.
440
         */
441
        public CreateDimensions(int width, int height, Integer maxDeadBoards) {
442
            super(maxDeadBoards);
3✔
443
            this.width = width;
3✔
444
            this.height = height;
3✔
445
        }
3✔
446

447
        @Override
448
        <T> T doVisit(CreateVisitor<T> visitor) {
449
            return visitor.dimensions(this);
3✔
450
        }
451

452
        @Override
453
        public int getArea() {
454
            return width * height;
3✔
455
        }
456
    }
457

458
    /** Some requests have the locations of boards. */
459
    abstract class HasBoardCoords extends CreateDescriptor {
460
        /** The logical coordinates, or {@code null}. */
461
        @Valid
462
        public final TriadCoords triad;
463

464
        /** The physical coordinates, or {@code null}. */
465
        @Valid
466
        public final PhysicalCoords physical;
467

468
        /** The network coordinates, or {@code null}. */
469
        @IPAddress(nullOK = true)
470
        public final String ip;
471

472
        private HasBoardCoords(TriadCoords triad, PhysicalCoords physical,
473
                String ip, Integer maxDeadBoards) {
474
            super(maxDeadBoards);
3✔
475
            this.triad = triad;
3✔
476
            this.physical = physical;
3✔
477
            this.ip = ip;
3✔
478
        }
3✔
479

480
        private static int get(Integer value) {
NEW
481
            return Objects.nonNull(value) ? value : 0;
×
482
        }
483

484
        @Keep
485
        @AssertTrue(message = "a method of locating a board must be provided")
486
        private boolean isLocated() {
NEW
487
            return nonNull(triad) || nonNull(physical) || nonNull(ip);
×
488
        }
489
    }
490

491
    /**
492
     * A request for a rectangle of triads rooted at a particular triad. No
493
     * option for using physical coordinates is supported with this method.
494
     */
495
    final class CreateDimensionsAt extends HasBoardCoords {
496
        /** Width requested, in triads. */
497
        @ValidTriadWidth
498
        public final int width;
499

500
        /** Height requested, in triads. */
501
        @ValidTriadHeight
502
        public final int height;
503

504
        /**
505
         * Create a request for a rectangle at a specific board. The board will
506
         * have a Z coordinate of 0.
507
         *
508
         * @param width
509
         *            Width requested, in triads.
510
         * @param height
511
         *            Height requested, in triads.
512
         * @param x
513
         *            The X coordinate of the root board of the request.
514
         * @param y
515
         *            The Y coordinate of the root board of the request.
516
         * @param maxDeadBoards
517
         *            The maximum number of dead boards tolerated in the
518
         *            allocation. Ignored when asking for a single board.
519
         */
520
        public CreateDimensionsAt(int width, int height, int x, int y,
521
                Integer maxDeadBoards) {
NEW
522
            super(new TriadCoords(x, y, 0), null, null, maxDeadBoards);
×
NEW
523
            this.width = width;
×
NEW
524
            this.height = height;
×
NEW
525
        }
×
526

527
        /**
528
         * Create a request for a rectangle at a specific board. The board will
529
         * have a Z coordinate of 0.
530
         *
531
         * @param width
532
         *            Width requested, in triads.
533
         * @param height
534
         *            Height requested, in triads.
535
         * @param x
536
         *            The X coordinate of the root board of the request.
537
         * @param y
538
         *            The Y coordinate of the root board of the request.
539
         * @param maxDeadBoards
540
         *            The maximum number of dead boards tolerated in the
541
         *            allocation. Ignored when asking for a single board.
542
         */
543
        public CreateDimensionsAt(int width, int height, Integer x, Integer y,
544
                Integer maxDeadBoards) {
NEW
545
            super(new TriadCoords(HasBoardCoords.get(x), HasBoardCoords.get(y),
×
546
                    0), null, null, maxDeadBoards);
NEW
547
            this.width = width;
×
NEW
548
            this.height = height;
×
NEW
549
        }
×
550

551
        /**
552
         * Create a request for a rectangle at a specific board. The board must
553
         * have a Z coordinate of 0.
554
         *
555
         * @param width
556
         *            Width requested, in triads.
557
         * @param height
558
         *            Height requested, in triads.
559
         * @param x
560
         *            The X coordinate of the root board of the request.
561
         * @param y
562
         *            The Y coordinate of the root board of the request.
563
         * @param z
564
         *            The Z coordinate of the root board of the request.
565
         * @param maxDeadBoards
566
         *            The maximum number of dead boards tolerated in the
567
         *            allocation. Ignored when asking for a single board.
568
         */
569
        public CreateDimensionsAt(int width, int height, int x, int y, int z,
570
                Integer maxDeadBoards) {
NEW
571
            super(new TriadCoords(x, y, z), null, null, maxDeadBoards);
×
NEW
572
            this.width = width;
×
NEW
573
            this.height = height;
×
NEW
574
        }
×
575

576
        /**
577
         * Create a request for a rectangle at a specific board. The board must
578
         * have a Z coordinate of 0.
579
         *
580
         * @param width
581
         *            Width requested, in triads.
582
         * @param height
583
         *            Height requested, in triads.
584
         * @param x
585
         *            The X coordinate of the root board of the request.
586
         * @param y
587
         *            The Y coordinate of the root board of the request.
588
         * @param z
589
         *            The Z coordinate of the root board of the request.
590
         * @param maxDeadBoards
591
         *            The maximum number of dead boards tolerated in the
592
         *            allocation. Ignored when asking for a single board.
593
         */
594
        public CreateDimensionsAt(int width, int height, Integer x, Integer y,
595
                Integer z, Integer maxDeadBoards) {
NEW
596
            super(new TriadCoords(HasBoardCoords.get(x), HasBoardCoords.get(y),
×
NEW
597
                    HasBoardCoords.get(z)), null, null, maxDeadBoards);
×
NEW
598
            this.width = width;
×
NEW
599
            this.height = height;
×
NEW
600
        }
×
601

602
        /**
603
         * Create a request for a rectangle at a specific board. The board must
604
         * have a Z coordinate of 0.
605
         *
606
         * @param width
607
         *            Width requested, in triads.
608
         * @param height
609
         *            Height requested, in triads.
610
         * @param ip
611
         *            The network address of the root board of the request.
612
         * @param maxDeadBoards
613
         *            The maximum number of dead boards tolerated in the
614
         *            allocation. Ignored when asking for a single board.
615
         */
616
        public CreateDimensionsAt(int width, int height, String ip,
617
                Integer maxDeadBoards) {
618
            super(null, null, ip, maxDeadBoards);
3✔
619
            this.width = width;
3✔
620
            this.height = height;
3✔
621
        }
3✔
622

623
        private CreateDimensionsAt(int width, int height,
624
                PhysicalCoords physical, Integer maxDeadBoards) {
NEW
625
            super(null, physical, null, maxDeadBoards);
×
NEW
626
            this.width = width;
×
NEW
627
            this.height = height;
×
NEW
628
        }
×
629

630
        /**
631
         * Create a request for a rectangle at a specific board. The board must
632
         * have a Z coordinate of 0.
633
         *
634
         * @param width
635
         *            Width requested, in triads.
636
         * @param height
637
         *            Height requested, in triads.
638
         * @param cabinet
639
         *            The cabinet number of the root board of the request.
640
         * @param frame
641
         *            The frame number of the root board.
642
         * @param board
643
         *            The board number of the root board.
644
         * @param maxDeadBoards
645
         *            The maximum number of dead boards tolerated in the
646
         *            allocation. Ignored when asking for a single board.
647
         * @return Descriptor
648
         */
649
        public static CreateDimensionsAt physical(int width, int height,
650
                int cabinet, int frame, int board, Integer maxDeadBoards) {
651
            // Done like this to avoid syntactic ambiguity
NEW
652
            return new CreateDimensionsAt(width, height,
×
653
                    new PhysicalCoords(cabinet, frame, board), maxDeadBoards);
654
        }
655

656
        /**
657
         * Create a request for a rectangle at a specific board. The board must
658
         * have a Z coordinate of 0.
659
         *
660
         * @param width
661
         *            Width requested, in triads.
662
         * @param height
663
         *            Height requested, in triads.
664
         * @param cabinet
665
         *            The cabinet number of the root board of the request.
666
         * @param frame
667
         *            The frame number of the root board.
668
         * @param board
669
         *            The board number of the root board.
670
         * @param maxDeadBoards
671
         *            The maximum number of dead boards tolerated in the
672
         *            allocation. Ignored when asking for a single board.
673
         * @return Descriptor
674
         */
675
        public static CreateDimensionsAt physical(int width, int height,
676
                Integer cabinet, Integer frame, Integer board,
677
                Integer maxDeadBoards) {
678
            // Done like this to avoid syntactic ambiguity
NEW
679
            return new CreateDimensionsAt(width, height,
×
NEW
680
                    new PhysicalCoords(HasBoardCoords.get(cabinet),
×
NEW
681
                            HasBoardCoords.get(frame),
×
NEW
682
                            HasBoardCoords.get(board)),
×
683
                    maxDeadBoards);
684
        }
685

686
        @Override
687
        <T> T doVisit(CreateVisitor<T> visitor) {
688
            return visitor.dimensionsAt(this);
3✔
689
        }
690

691
        @Override
692
        public int getArea() {
693
            return width * height * TRIAD_DEPTH;
3✔
694
        }
695
    }
696

697
    /**
698
     * A request for a specific board.
699
     */
700
    final class CreateBoard extends HasBoardCoords {
701
        private CreateBoard(TriadCoords triad, PhysicalCoords physical,
702
                String ip) {
703
            super(triad, physical, ip, null);
3✔
704
        }
3✔
705

706
        /**
707
         * Create a request for a specific board.
708
         *
709
         * @param x
710
         *            The X coordinate of the board.
711
         * @param y
712
         *            The Y coordinate of the board.
713
         * @param z
714
         *            The Z coordinate of the board.
715
         * @return Descriptor
716
         */
717
        public static CreateBoard triad(int x, int y, int z) {
718
            return new CreateBoard(new TriadCoords(x, y, z), null, null);
3✔
719
        }
720

721
        /**
722
         * Create a request for a specific board.
723
         *
724
         * @param cabinet
725
         *            The cabinet number of the board.
726
         * @param frame
727
         *            The frame number of the board.
728
         * @param board
729
         *            The board number of the board.
730
         * @return Descriptor
731
         */
732
        public static CreateBoard physical(int cabinet, int frame, int board) {
NEW
733
            return new CreateBoard(null,
×
734
                    new PhysicalCoords(cabinet, frame, board), null);
735
        }
736

737
        /**
738
         * Create a request for a specific board.
739
         *
740
         * @param ip
741
         *            The network address of the board.
742
         * @return Descriptor
743
         */
744
        public static CreateBoard address(@IPAddress String ip) {
NEW
745
            return new CreateBoard(null, null, ip);
×
746
        }
747

748
        @Override
749
        <T> T doVisit(CreateVisitor<T> visitor) {
750
            return visitor.board(this);
3✔
751
        }
752

753
        @Override
754
        public int getArea() {
755
            return 1;
3✔
756
        }
757
    }
758

759
    /**
760
     * Visitor for {@link CreateDescriptor}.
761
     *
762
     * @param <T>
763
     *            The type of the result of visiting.
764
     */
765
    interface CreateVisitor<T> {
766
        /**
767
         * Visit a descriptor.
768
         *
769
         * @param createNumBoards
770
         *            The descriptor.
771
         * @return The result of the visiting.
772
         */
773
        T numBoards(@NotNull CreateNumBoards createNumBoards);
774

775
        /**
776
         * Visit a descriptor.
777
         *
778
         * @param createDimensionsAt
779
         *            The descriptor.
780
         * @return The result of the visiting.
781
         */
782
        T dimensionsAt(@NotNull CreateDimensionsAt createDimensionsAt);
783

784
        /**
785
         * Visit a descriptor.
786
         *
787
         * @param createDimensions
788
         *            The descriptor.
789
         * @return The result of the visiting.
790
         */
791
        T dimensions(@NotNull CreateDimensions createDimensions);
792

793
        /**
794
         * Visit a descriptor.
795
         *
796
         * @param createBoard
797
         *            The descriptor.
798
         * @return The result of the visiting.
799
         */
800
        T board(@NotNull CreateBoard createBoard);
801
    }
802

803
    /**
804
     * A thing that may be waited upon.
805
     *
806
     * @author Donal Fellows
807
     */
808
    interface Waitable {
809
        /**
810
         * Wait for the object to (maybe) change, or for the timeout to expire.
811
         * This is a best-effort method.
812
         * <p>
813
         * This method does <em>not</em> throw {@link InterruptedException}; on
814
         * interruption, it simply returns early (but the
815
         * {@linkplain Thread#interrupted() interrupted status} of the thread is
816
         * set).
817
         *
818
         * @param timeout
819
         *            How long to wait.
820
         * @return True if the wait was interrupted,
821
         *         False if the timeout expired
822
         */
823
        boolean waitForChange(@NotNull Duration timeout);
824
    }
825

826
    /**
827
     * Describes a particular job known to the allocator.
828
     *
829
     * @author Donal Fellows
830
     */
831
    interface Job extends Waitable {
832
        /** @return Job ID */
833
        int getId();
834

835
        /**
836
         * Update the keepalive.
837
         *
838
         * @param keepaliveAddress
839
         *            Where was the access from.
840
         */
841
        void access(@NotNull @IPAddress String keepaliveAddress);
842

843
        /**
844
         * Mark the job as destroyed. To do this to an already destroyed job is
845
         * a no-op.
846
         *
847
         * @param reason
848
         *            Why the job is being destroyed.
849
         */
850
        void destroy(String reason);
851

852
        /**
853
         * Power a job on or off.
854
         *
855
         * @param power True for on, False for off
856
         */
857
        void setPower(boolean power);
858

859
        /**
860
         * @return The state of the job.
861
         */
862
        JobState getState();
863

864
        /**
865
         * @return When the job started.
866
         */
867
        Instant getStartTime();
868

869
        /**
870
         * @return Host address that issued last keepalive event, or
871
         *         {@link Optional#empty() empty()} if this information is not
872
         *         available to the current user.
873
         */
874
        Optional<String> getKeepaliveHost();
875

876
        /**
877
         * @return Time of the last keepalive event.
878
         */
879
        Instant getKeepaliveTimestamp();
880

881
        /**
882
         * @return The creator of the job. {@link Optional#empty() empty()} if
883
         *         this is not available to the current user.
884
         */
885
        Optional<String> getOwner();
886

887
        /**
888
         * @return The serialized original request to create the job.
889
         *         {@link Optional#empty() empty()} if this is not available to
890
         *         the current user.
891
         */
892
        Optional<byte[]> getOriginalRequest();
893

894
        /**
895
         * @return When the job finished. {@link Optional#empty() empty()} if
896
         *         the job is not yet finished.
897
         */
898
        Optional<Instant> getFinishTime();
899

900
        /**
901
         * @return Why the job died. Might be {@link Optional#empty() empty()}
902
         *         if this isn't known (including if the job is alive).
903
         */
904
        Optional<String> getReason();
905

906
        /**
907
         * @return The (sub-)machine allocated to the job.
908
         *         {@link Optional#empty() empty()} if no resources allocated.
909
         */
910
        Optional<SubMachine> getMachine();
911

912
        /**
913
         * Locate a board within the allocation.
914
         *
915
         * @param x
916
         *            The X coordinate of a chip on the board of interest.
917
         * @param y
918
         *            The Y coordinate of a chip on the board of interest.
919
         * @return The location, if resources allocated and the location maps.
920
         *         {@link Optional#empty() empty()} otherwise.
921
         */
922
        Optional<BoardLocation> whereIs(@ValidX int x, @ValidY int y);
923

924
        /**
925
         * @return The absolute location of root chip. {@link Optional#empty()
926
         *         empty()} if no resources allocated.
927
         */
928
        Optional<ChipLocation> getRootChip();
929

930
        /**
931
         * @return the allocated width of the job's rectangle of triads, or
932
         *         {@link Optional#empty() empty()} if not allocated (or not
933
         *         known).
934
         */
935
        Optional<Integer> getWidth();
936

937
        /**
938
         * @return the allocated height of the job's rectangle of triads, or
939
         *         {@link Optional#empty() empty()} if not allocated (or not
940
         *         known).
941
         */
942
        Optional<Integer> getHeight();
943

944
        /**
945
         * @return the allocated depth of this sub-machine, or
946
         *         {@link Optional#empty() empty()} if not allocated (or not
947
         *         known). When supplied, will be 1 (single board) or 3 (by
948
         *         triad)
949
         */
950
        Optional<Integer> getDepth();
951

952
        /**
953
         * Report an issue with some boards in the job.
954
         *
955
         * @param reqBody
956
         *            The description of the issue.
957
         * @param permit
958
         *            Who is actually reporting this?
959
         * @return The text part of the response
960
         */
961
        String reportIssue(IssueReportRequest reqBody, Permit permit);
962

963
        /**
964
         * Note that a proxy has been set up for the job. This allows the proxy
965
         * to be closed when the job state changes. (The proxy may already be
966
         * closed at that point.)
967
         *
968
         * @param proxy
969
         *            The proxy.
970
         */
971
        void rememberProxy(ProxyCore proxy);
972

973
        /**
974
         * Note that a proxy has been dropped from the job and doesn't need to
975
         * be remembered any more.
976
         *
977
         * @param proxy
978
         *            The proxy.
979
         */
980
        void forgetProxy(ProxyCore proxy);
981

982
        /**
983
         * Get a way to talk to the machine directly.  Note that it might not be
984
         * booted...
985
         *
986
         * @return The transceiver interface.
987
         * @throws IOException if there is an issue creating the transceiver.
988
         * @throws InterruptedException if the operation is interrupted.
989
         * @throws SpinnmanException
990
         *         if there is an issue speaking to the machine.
991
         */
992
        TransceiverInterface getTransceiver()
993
                throws IOException, InterruptedException, SpinnmanException;
994
    }
995

996
    /**
997
     * Describes a list of jobs known to the allocator.
998
     *
999
     * @author Donal Fellows
1000
     */
1001
    interface Jobs extends Waitable {
1002
        /**
1003
         * @return The job IDs.
1004
         */
1005
        List<Integer> ids();
1006

1007
        /**
1008
         * @return The jobs. Simplified view only. (No keepalive host or owner
1009
         *         information.)
1010
         */
1011
        List<Job> jobs();
1012

1013
        /**
1014
         * @param duration
1015
         *            How long to wait for a change.
1016
         * @return The set of jobs that have changed.
1017
         */
1018
        Collection<Integer> getChanged(Duration duration);
1019
    }
1020

1021
    /**
1022
     * Describes a particular machine known to the allocator. Must implement
1023
     * equality by ID or name (both are unique).
1024
     *
1025
     * @author Donal Fellows
1026
     */
1027
    interface Machine extends Waitable {
1028
        /** @return The ID of the machine. Unique. */
1029
        int getId();
1030

1031
        /** @return The name of the machine. Unique. */
1032
        String getName();
1033

1034
        /** @return The tags associated with the machine. */
1035
        Set<String> getTags();
1036

1037
        /** @return The width of the machine. */
1038
        int getWidth();
1039

1040
        /** @return The height of the machine. */
1041
        int getHeight();
1042

1043
        /** @return Whether the machine wraps in the horizontal direction. */
1044
        boolean isHorizonallyWrapped();
1045

1046
        /** @return Whether the machine wraps in the vertical direction. */
1047
        boolean isVerticallyWrapped();
1048

1049
        /** @return Whether this machine is currently in service. */
1050
        boolean isInService();
1051

1052
        /**
1053
         * The IDs of boards marked as dead or otherwise taken out of service.
1054
         *
1055
         * @return A list of boards. Not modifiable.
1056
         */
1057
        List<BoardCoords> getDeadBoards();
1058

1059
        /**
1060
         * The links within the machine that are marked as dead or otherwise
1061
         * taken out of service. Note that this does not include links that lead
1062
         * out of the machine.
1063
         *
1064
         * @return A list of links. Not modifiable.
1065
         */
1066
        List<DownLink> getDownLinks();
1067

1068
        /**
1069
         * Get a description of the location of a board given the global
1070
         * coordinates of a chip on it.
1071
         *
1072
         * @param chipLocation
1073
         *            Global chip coordinates.
1074
         * @return Board location description
1075
         */
1076
        Optional<BoardLocation> getBoardByChip(
1077
                @Valid @NotNull HasChipLocation chipLocation);
1078

1079
        /**
1080
         * Get a description of the location of a board given the physical
1081
         * coordinates of the board.
1082
         *
1083
         * @param coords
1084
         *            PhysicalCoordinates
1085
         * @return Board location description
1086
         */
1087
        Optional<BoardLocation> getBoardByPhysicalCoords(
1088
                @Valid @NotNull PhysicalCoords coords);
1089

1090
        /**
1091
         * Get a description of the location of a board given the triad
1092
         * coordinates of the board.
1093
         *
1094
         * @param coords
1095
         *            Triad coordinates.
1096
         * @return Board location description
1097
         */
1098
        Optional<BoardLocation> getBoardByLogicalCoords(
1099
                @Valid @NotNull TriadCoords coords);
1100

1101
        /**
1102
         * Get a description of the location of a board given the address of its
1103
         * ethernet chip.
1104
         *
1105
         * @param address
1106
         *            IP address of the board (in {@code 0.0.0.0} form; will be
1107
         *            matched exactly by the values in the DB).
1108
         * @return Board location description
1109
         */
1110
        Optional<BoardLocation> getBoardByIPAddress(@IPAddress String address);
1111

1112
        /**
1113
         * @return The IP address of the BMP of the root board of the machine.
1114
         */
1115
        String getRootBoardBMPAddress();
1116

1117
        /** @return The boards supported by the machine. */
1118
        List<Integer> getBoardNumbers();
1119

1120
        /** @return The IDs of boards currently available to be allocated. */
1121
        List<Integer> getAvailableBoards();
1122

1123
        /**
1124
         * Get the address of a particular BMP of a machine.
1125
         *
1126
         * @param bmp
1127
         *            The BMP coordinates (cabinet, frame).
1128
         * @return The IP address of the BMP.
1129
         */
1130
        String getBMPAddress(@Valid BMPCoords bmp);
1131

1132
        /**
1133
         * Get the board numbers managed by a particular BMP of a machine.
1134
         *
1135
         * @param bmp
1136
         *            The BMP coordinates( cabinet, frame).
1137
         * @return The board numbers managed by that BMP.
1138
         */
1139
        List<Integer> getBoardNumbers(@Valid BMPCoords bmp);
1140
    }
1141

1142
    /**
1143
     * Describes the locations of boards in a machine. Note that instances of
1144
     * this class are expected to be fully instantiated; reading from them will
1145
     * <em>not</em> touch the database.
1146
     *
1147
     * @author Donal Fellows
1148
     */
1149
    interface BoardLocation {
1150
        /**
1151
         * Get the location of the characteristic chip of a board. This is
1152
         * usually the root chip of the board.
1153
         *
1154
         * @return chip location, in <em>global</em> (whole machine) coordinates
1155
         */
1156
        ChipLocation getBoardChip();
1157

1158
        /**
1159
         * Get the location of this board location relative to another global
1160
         * location (the global location of the root chip of an allocation).
1161
         *
1162
         * @param rootChip
1163
         *            The global location of the root chip of an allocation that
1164
         *            we are converting this board location to be relative to.
1165
         * @return chip location, in <em>relative</em> (single job) coordinates
1166
         */
1167
        ChipLocation getChipRelativeTo(@NotNull ChipLocation rootChip);
1168

1169
        /**
1170
         * What machine is the board on?
1171
         *
1172
         * @return name of machine
1173
         */
1174
        String getMachine();
1175

1176
        /**
1177
         * Where is the board logically within its machine?
1178
         *
1179
         * @return a triad location descriptor
1180
         */
1181
        BoardCoordinates getLogical();
1182

1183
        /**
1184
         * Where is the board physically in its machine?
1185
         *
1186
         * @return a cabinet/frame/board triple
1187
         */
1188
        BoardPhysicalCoordinates getPhysical();
1189

1190
        /**
1191
         * Where is the chip of interest? Usually the root chip of the board.
1192
         *
1193
         * @return a chip location, in <em>global</em> (whole machine)
1194
         *         coordinates
1195
         */
1196
        ChipLocation getChip();
1197

1198
        /**
1199
         * What job is the board allocated to? May be {@code null} for an
1200
         * unallocated board.
1201
         *
1202
         * @return a limited version of a job.
1203
         */
1204
        Job getJob();
1205
    }
1206

1207
    /** A view of part of a machine that is allocated to a job. */
1208
    interface SubMachine {
1209
        /** @return The machine that this sub-machine is part of. */
1210
        Machine getMachine();
1211

1212
        /** @return The root X coordinate of this sub-machine. */
1213
        int getRootX();
1214

1215
        /** @return The root Y coordinate of this sub-machine. */
1216
        int getRootY();
1217

1218
        /** @return The root Z coordinate of this sub-machine. */
1219
        int getRootZ();
1220

1221
        /** @return The width of this sub-machine, in triads. */
1222
        int getWidth();
1223

1224
        /** @return The height of this sub-machine, in triads. */
1225
        int getHeight();
1226

1227
        /**
1228
         * @return The depth of this sub-machine. 1 (single board) or 3 (by
1229
         *         triad)
1230
         */
1231
        int getDepth();
1232

1233
        /** @return The connection details of this sub-machine. */
1234
        List<ConnectionInfo> getConnections();
1235

1236
        /** @return The board locations of this sub-machine. */
1237
        List<BoardCoordinates> getBoards();
1238

1239
        /** @return Whether this sub-machine is switched on. */
1240
        PowerState getPower();
1241

1242
        /**
1243
         * Set whether this sub-machine is switched on. Note that actually
1244
         * changing the power of a sub-machine can take some time.
1245
         *
1246
         * @param powerState
1247
         *            What to set the power state to.
1248
         */
1249
        void setPower(@NotNull PowerState powerState);
1250
    }
1251
}
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