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

SpiNNakerManchester / JavaSpiNNaker / 6310285782

26 Sep 2023 08:47AM UTC coverage: 36.367% (-0.5%) from 36.866%
6310285782

Pull #658

github

dkfellows
Merge branch 'master' into java-17
Pull Request #658: Update Java version to 17 and JEE to 9

1675 of 1675 new or added lines in 266 files covered. (100.0%)

8368 of 23010 relevant lines covered (36.37%)

0.36 hits per line

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

39.39
/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 org.slf4j.LoggerFactory.getLogger;
19
import static uk.ac.manchester.spinnaker.messages.Constants.SCP_SCAMP_PORT;
20
import static uk.ac.manchester.spinnaker.utils.InetFactory.getByName;
21
import static uk.ac.manchester.spinnaker.utils.Ping.ping;
22

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

30
import org.slf4j.Logger;
31
import org.springframework.beans.factory.annotation.Autowired;
32
import org.springframework.stereotype.Service;
33

34
import com.google.errorprone.annotations.RestrictedApi;
35
import com.google.errorprone.annotations.concurrent.GuardedBy;
36

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

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

70
        private record Key(String machine, BMPCoords bmp) {
1✔
71
        }
72

73
        @GuardedBy("itself")
1✔
74
        private final Map<Key, BMPTransceiverInterface> txrxMap = new HashMap<>();
75

76
        @Autowired
77
        private ServiceMasterControl control;
78

79
        @Autowired
80
        private TxrxProperties props;
81

82
        @PostConstruct
83
        private void setup() {
84
                // Whenever the useDummyBMP property is changed, flush the cache
85
                control.addUseDummyBMPListener(e -> {
1✔
86
                        synchronized (txrxMap) {
×
87
                                try {
88
                                        closeTransceivers();
×
89
                                } catch (Exception ex) {
×
90
                                        log.warn("problem closing transceivers", ex);
×
91
                                }
×
92
                                txrxMap.clear();
×
93
                        }
×
94
                });
×
95
        }
1✔
96

97
        @Override
98
        public BMPTransceiverInterface getTransciever(Machine machineDescription,
99
                        BMPCoords bmp)
100
                        throws IOException, SpinnmanException, InterruptedException {
101
                try {
102
                        synchronized (txrxMap) {
1✔
103
                                return txrxMap
1✔
104
                                                .computeIfAbsent(
1✔
105
                                                new Key(machineDescription.getName(), bmp),
1✔
106
                                                __ -> makeTransceiver(machineDescription, bmp));
1✔
107
                        }
108
                } catch (TransceiverFactoryException e) {
×
109
                        var t = e.getCause();
×
110
                        if (t instanceof IOException ioe) {
×
111
                                throw ioe;
×
112
                        } else if (t instanceof SpinnmanException se) {
×
113
                                throw se;
×
114
                        } else if (t instanceof InterruptedException ie) {
×
115
                                throw ie;
×
116
                        }
117
                        throw e;
×
118
                }
119
        }
120

121
        private static class TransceiverFactoryException extends RuntimeException {
122
                @Serial
123
                private static final long serialVersionUID = 2102592240724419836L;
124

125
                TransceiverFactoryException(String msg, Exception e) {
126
                        super(msg, e);
×
127
                }
×
128
        }
129

130
        private final ValueHolder<Blacklist> setBlacklist = new ValueHolder<>();
1✔
131

132
        private TestAPI.TestTransceiverFactory testFactory = null;
1✔
133

134
        private BMPTransceiverInterface makeTransceiver(Machine machineDescription,
135
                        BMPCoords bmp) {
136
                var connData = makeConnectionData(machineDescription, bmp);
1✔
137
                try {
138
                        if (control.isUseDummyBMP()) {
1✔
139
                                return testFactory.create(machineDescription.getName(),
1✔
140
                                                connData, setBlacklist);
141
                        } else {
142
                                return makeTransceiver(connData);
×
143
                        }
144
                } catch (IOException | SpinnmanException | InterruptedException e) {
×
145
                        throw new TransceiverFactoryException(
×
146
                                        "failed to build BMP transceiver", e);
147
                }
148
        }
149

150
        private BMPConnectionData makeConnectionData(Machine machine,
151
                        BMPCoords bmp) {
152
                try {
153
                        var address = machine.getBMPAddress(bmp);
1✔
154
                        var boards = machine.getBoardNumbers(bmp);
1✔
155
                        return new BMPConnectionData(0, 0, getByName(address), boards,
1✔
156
                                        SCP_SCAMP_PORT);
1✔
157
                } catch (IOException e) {
×
158
                        throw new TransceiverFactoryException(
×
159
                                        "failed to build address of BMP transceiver", e);
160
                }
161
        }
162

163
        /**
164
         * Build a transceiver connection.
165
         * <p>
166
         * The original spalloc server <em>also</em> does everything through the
167
         * root BMP; the BMPs communicate with each other if necessary. I believe
168
         * that communication is via an I<sup>2</sup>C bus, but I might be wrong.
169
         *
170
         * @param data
171
         *            The information about the BMP and the boards to manage.
172
         * @throws IOException
173
         *             If network access fails
174
         * @throws SpinnmanException
175
         *             If transceiver building fails
176
         * @throws InterruptedException
177
         *             If the communications were interrupted.
178
         */
179
        private Transceiver makeTransceiver(BMPConnectionData data)
180
                        throws IOException, SpinnmanException, InterruptedException {
181
                int count = 0;
×
182
                while (true) {
183
                        try {
184
                                return new Transceiver(null, List.of(new BMPConnection(data)),
×
185
                                                null, null, null, null, null);
186
                        } catch (ProcessException e) {
×
187
                                if (e.getCause() instanceof BMPSendTimedOutException
×
188
                                                && ++count > props.getBuildAttempts()) {
×
189
                                        log.error("completely failed to connect to BMP {}; "
×
190
                                                        + "service is unstable!", data);
191
                                        throw e;
×
192
                                }
193
                                log.error("failed to connect to BMP; will ping and retry", e);
×
194
                                log.debug("ping result was {}", ping(data.ipAddress()));
×
195
                        }
×
196
                }
197
        }
198

199
        private Collection<BMPTransceiverInterface> transceivers() {
200
                synchronized (txrxMap) {
×
201
                        return List.copyOf(txrxMap.values());
×
202
                }
203
        }
204

205
        @PreDestroy
206
        void closeTransceivers() throws Exception {
207
                for (var txrx : transceivers()) {
×
208
                        txrx.close();
×
209
                }
×
210
        }
×
211

212
        /**
213
         * Not a public API! Operations for testing only.
214
         *
215
         * @hidden
216
         */
217
        @ForTestingOnly
218
        public interface TestAPI {
219
                /** @return The current blacklist. */
220
                Blacklist getCurrentBlacklist();
221

222
                /**
223
                 * @param factory
224
                 *            The mock transceiver factory to use.
225
                 */
226
                void setFactory(TestTransceiverFactory factory);
227

228
                /**
229
                 * Not a public API! A factory for transceivers. Use to install a
230
                 * suitable mock.
231
                 *
232
                 * @hidden
233
                 */
234
                interface TestTransceiverFactory {
235
                        /**
236
                         * Make a test transceiver.
237
                         *
238
                         * @param machineName
239
                         *            The name of the machine.
240
                         * @param data
241
                         *            The connection data.
242
                         * @param setBlacklist
243
                         *            Where to record the current blacklist
244
                         * @return Transceiver for testing.
245
                         */
246
                        BMPTransceiverInterface create(String machineName,
247
                                        BMPConnectionData data,
248
                                        ValueHolder<Blacklist> setBlacklist);
249
                }
250
        }
251

252
        /**
253
         * Not a public API! Do not call outside of test code!
254
         *
255
         * @return The test interface.
256
         * @deprecated This interface is just for testing.
257
         * @hidden
258
         */
259
        @ForTestingOnly
260
        @RestrictedApi(explanation = "just for testing", link = "index.html",
261
                        allowedOnPath = ".*/src/test/java/.*")
262
        @Deprecated
263
        public final TestAPI getTestAPI() {
264
                ForTestingOnly.Utils.checkForTestClassOnStack();
1✔
265
                return new TestAPI() {
1✔
266
                        @Override
267
                        public Blacklist getCurrentBlacklist() {
268
                                synchronized (setBlacklist) {
1✔
269
                                        return setBlacklist.getValue();
1✔
270
                                }
271
                        }
272

273
                        @Override
274
                        public void setFactory(TestTransceiverFactory factory) {
275
                                testFactory = factory;
1✔
276
                        }
1✔
277
                };
278
        }
279
}
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