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

SpiNNakerManchester / JavaSpiNNaker / 6168056629

12 Sep 2023 11:09AM UTC coverage: 36.957% (-0.09%) from 37.05%
6168056629

push

github

web-flow
Merge pull request #1038 from SpiNNakerManchester/dependabot/maven/org.webjars-swagger-ui-5.6.1

Bump org.webjars:swagger-ui from 5.4.2 to 5.6.1

8676 of 23476 relevant lines covered (36.96%)

0.74 hits per line

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

44.59
/SpiNNaker-allocserv/src/main/java/uk/ac/manchester/spinnaker/alloc/bmp/TransceiverFactory.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.bmp;
17

18
import static java.util.Objects.hash;
19
import static org.slf4j.LoggerFactory.getLogger;
20
import static uk.ac.manchester.spinnaker.messages.Constants.SCP_SCAMP_PORT;
21
import static uk.ac.manchester.spinnaker.utils.InetFactory.getByName;
22
import static uk.ac.manchester.spinnaker.utils.Ping.ping;
23

24
import java.io.IOException;
25
import java.util.Collection;
26
import java.util.HashMap;
27
import java.util.List;
28
import java.util.Map;
29

30
import javax.annotation.PostConstruct;
31
import javax.annotation.PreDestroy;
32

33
import org.slf4j.Logger;
34
import org.springframework.beans.factory.annotation.Autowired;
35
import org.springframework.stereotype.Service;
36

37
import com.google.errorprone.annotations.RestrictedApi;
38
import com.google.errorprone.annotations.concurrent.GuardedBy;
39

40
import uk.ac.manchester.spinnaker.alloc.ForTestingOnly;
41
import uk.ac.manchester.spinnaker.alloc.ServiceMasterControl;
42
import uk.ac.manchester.spinnaker.alloc.SpallocProperties.TxrxProperties;
43
import uk.ac.manchester.spinnaker.alloc.allocator.SpallocAPI.Machine;
44
import uk.ac.manchester.spinnaker.connections.BMPConnection;
45
import uk.ac.manchester.spinnaker.machine.board.BMPCoords;
46
import uk.ac.manchester.spinnaker.messages.model.BMPConnectionData;
47
import uk.ac.manchester.spinnaker.messages.model.Blacklist;
48
import uk.ac.manchester.spinnaker.transceiver.BMPSendTimedOutException;
49
import uk.ac.manchester.spinnaker.transceiver.BMPTransceiverInterface;
50
import uk.ac.manchester.spinnaker.transceiver.ProcessException;
51
import uk.ac.manchester.spinnaker.transceiver.SpinnmanException;
52
import uk.ac.manchester.spinnaker.transceiver.Transceiver;
53
import uk.ac.manchester.spinnaker.utils.ValueHolder;
54

55
/**
56
 * Creates transceivers for talking to the BMPs of machines. Note that each
57
 * machine only has the one BMP that is talked to, and only ever one transceiver
58
 * that is used to do it.
59
 * <p>
60
 * Can support running with a dummy transceiver (but not in production, of
61
 * course). Set the {@code spalloc.transceiver.dummy} configuration value to
62
 * {@code true} to enable that.
63
 *
64
 * @author Donal Fellows
65
 */
66
@Service("transceiverFactory")
67
public class TransceiverFactory
2✔
68
                implements TransceiverFactoryAPI<BMPTransceiverInterface> {
69
        private static final Logger log = getLogger(TransceiverFactory.class);
2✔
70

71
        private static final class Key {
72
                final String machine;
73

74
                final BMPCoords bmp;
75

76
                Key(String machine, BMPCoords bmp) {
2✔
77
                        this.machine = machine;
2✔
78
                        this.bmp = bmp;
2✔
79
                }
2✔
80

81
                @Override
82
                public boolean equals(Object o) {
83
                        if (o instanceof Key) {
2✔
84
                                var other = (Key) o;
2✔
85
                                return machine.equals(other.machine) && bmp.equals(other.bmp);
2✔
86
                        }
87
                        return false;
×
88
                }
89

90
                @Override
91
                public int hashCode() {
92
                        return hash(machine, bmp);
2✔
93
                }
94
        }
95

96
        @GuardedBy("itself")
2✔
97
        private final Map<Key, BMPTransceiverInterface> txrxMap = new HashMap<>();
98

99
        @Autowired
100
        private ServiceMasterControl control;
101

102
        @Autowired
103
        private TxrxProperties props;
104

105
        @PostConstruct
106
        private void setup() {
107
                // Whenever the useDummyBMP property is changed, flush the cache
108
                control.addUseDummyBMPListener(e -> {
2✔
109
                        synchronized (txrxMap) {
×
110
                                try {
111
                                        closeTransceivers();
×
112
                                } catch (Exception ex) {
×
113
                                        log.warn("problem closing transceivers", ex);
×
114
                                }
×
115
                                txrxMap.clear();
×
116
                        }
×
117
                });
×
118
        }
2✔
119

120
        @Override
121
        public BMPTransceiverInterface getTransciever(Machine machineDescription,
122
                        BMPCoords bmp)
123
                        throws IOException, SpinnmanException, InterruptedException {
124
                try {
125
                        synchronized (txrxMap) {
2✔
126
                                return txrxMap
2✔
127
                                                .computeIfAbsent(
2✔
128
                                                new Key(machineDescription.getName(), bmp),
2✔
129
                                                __ -> makeTransceiver(machineDescription, bmp));
2✔
130
                        }
131
                } catch (TransceiverFactoryException e) {
×
132
                        var t = e.getCause();
×
133
                        if (t instanceof IOException) {
×
134
                                throw (IOException) t;
×
135
                        } else if (t instanceof SpinnmanException) {
×
136
                                throw (SpinnmanException) t;
×
137
                        } else if (t instanceof InterruptedException) {
×
138
                                throw (InterruptedException) t;
×
139
                        }
140
                        throw e;
×
141
                }
142
        }
143

144
        private static class TransceiverFactoryException extends RuntimeException {
145
                private static final long serialVersionUID = 2102592240724419836L;
146

147
                TransceiverFactoryException(String msg, Exception e) {
148
                        super(msg, e);
×
149
                }
×
150
        }
151

152
        private final ValueHolder<Blacklist> setBlacklist = new ValueHolder<>();
2✔
153

154
        private TestAPI.TestTransceiverFactory testFactory = null;
2✔
155

156
        private BMPTransceiverInterface makeTransceiver(Machine machineDescription,
157
                        BMPCoords bmp) {
158
                var connData = makeConnectionData(machineDescription, bmp);
2✔
159
                try {
160
                        if (control.isUseDummyBMP()) {
2✔
161
                                return testFactory.create(machineDescription.getName(),
2✔
162
                                                connData, setBlacklist);
163
                        } else {
164
                                return makeTransceiver(connData);
×
165
                        }
166
                } catch (IOException | SpinnmanException | InterruptedException e) {
×
167
                        throw new TransceiverFactoryException(
×
168
                                        "failed to build BMP transceiver", e);
169
                }
170
        }
171

172
        private BMPConnectionData makeConnectionData(Machine machine,
173
                        BMPCoords bmp) {
174
                try {
175
                        var address = machine.getBMPAddress(bmp);
2✔
176
                        var boards = machine.getBoardNumbers(bmp);
2✔
177
                        return new BMPConnectionData(0, 0, getByName(address), boards,
2✔
178
                                        SCP_SCAMP_PORT);
2✔
179
                } catch (IOException e) {
×
180
                        throw new TransceiverFactoryException(
×
181
                                        "failed to build address of BMP transceiver", e);
182
                }
183
        }
184

185
        /**
186
         * Build a transceiver connection.
187
         * <p>
188
         * The original spalloc server <em>also</em> does everything through the
189
         * root BMP; the BMPs communicate with each other if necessary. I believe
190
         * that communication is via an I<sup>2</sup>C bus, but I might be wrong.
191
         *
192
         * @param data
193
         *            The information about the BMP and the boards to manage.
194
         * @throws IOException
195
         *             If network access fails
196
         * @throws SpinnmanException
197
         *             If transceiver building fails
198
         * @throws InterruptedException
199
         *             If the communications were interrupted.
200
         */
201
        private Transceiver makeTransceiver(BMPConnectionData data)
202
                        throws IOException, SpinnmanException, InterruptedException {
203
                int count = 0;
×
204
                while (true) {
205
                        try {
206
                                return new Transceiver(null, List.of(new BMPConnection(data)),
×
207
                                                null, null, null, null, null);
208
                        } catch (ProcessException e) {
×
209
                                if (e.getCause() instanceof BMPSendTimedOutException
×
210
                                                && ++count > props.getBuildAttempts()) {
×
211
                                        log.error("completely failed to connect to BMP {}; "
×
212
                                                        + "service is unstable!", data);
213
                                        throw e;
×
214
                                }
215
                                log.error("failed to connect to BMP; will ping and retry", e);
×
216
                                log.debug("ping result was {}", ping(data.ipAddress));
×
217
                        }
×
218
                }
219
        }
220

221
        private Collection<BMPTransceiverInterface> transceivers() {
222
                synchronized (txrxMap) {
×
223
                        return List.copyOf(txrxMap.values());
×
224
                }
225
        }
226

227
        @PreDestroy
228
        void closeTransceivers() throws Exception {
229
                for (var txrx : transceivers()) {
×
230
                        txrx.close();
×
231
                }
×
232
        }
×
233

234
        /**
235
         * Not a public API! Operations for testing only.
236
         *
237
         * @hidden
238
         */
239
        @ForTestingOnly
240
        public interface TestAPI {
241
                /** @return The current blacklist. */
242
                Blacklist getCurrentBlacklist();
243

244
                /**
245
                 * @param factory
246
                 *            The mock transceiver factory to use.
247
                 */
248
                void setFactory(TestTransceiverFactory factory);
249

250
                /**
251
                 * Not a public API! A factory for transceivers. Use to install a
252
                 * suitable mock.
253
                 *
254
                 * @hidden
255
                 */
256
                interface TestTransceiverFactory {
257
                        /**
258
                         * Make a test transceiver.
259
                         *
260
                         * @param machineName
261
                         *            The name of the machine.
262
                         * @param data
263
                         *            The connection data.
264
                         * @param setBlacklist
265
                         *            Where to record the current blacklist
266
                         * @return Transceiver for testing.
267
                         */
268
                        BMPTransceiverInterface create(String machineName,
269
                                        BMPConnectionData data,
270
                                        ValueHolder<Blacklist> setBlacklist);
271
                }
272
        }
273

274
        /**
275
         * Not a public API! Do not call outside of test code!
276
         *
277
         * @return The test interface.
278
         * @deprecated This interface is just for testing.
279
         * @hidden
280
         */
281
        @ForTestingOnly
282
        @RestrictedApi(explanation = "just for testing", link = "index.html",
283
                        allowedOnPath = ".*/src/test/java/.*")
284
        @Deprecated
285
        public final TestAPI getTestAPI() {
286
                ForTestingOnly.Utils.checkForTestClassOnStack();
2✔
287
                return new TestAPI() {
2✔
288
                        @Override
289
                        public Blacklist getCurrentBlacklist() {
290
                                synchronized (setBlacklist) {
2✔
291
                                        return setBlacklist.getValue();
2✔
292
                                }
293
                        }
294

295
                        @Override
296
                        public void setFactory(TestTransceiverFactory factory) {
297
                                testFactory = factory;
2✔
298
                        }
2✔
299
                };
300
        }
301
}
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