2 * Copyright (c) 2015 Cisco Systems and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.dsbenchmark;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableClassToInstanceMap;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.util.Collections;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.atomic.AtomicReference;
18 import javax.annotation.PreDestroy;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.dsbenchmark.listener.DsbenchmarkListenerProvider;
22 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaDelete;
23 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaRead;
24 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaWrite;
25 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomDelete;
26 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomRead;
27 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomWrite;
28 import org.opendaylight.dsbenchmark.txchain.TxchainBaDelete;
29 import org.opendaylight.dsbenchmark.txchain.TxchainBaRead;
30 import org.opendaylight.dsbenchmark.txchain.TxchainBaWrite;
31 import org.opendaylight.dsbenchmark.txchain.TxchainDomDelete;
32 import org.opendaylight.dsbenchmark.txchain.TxchainDomRead;
33 import org.opendaylight.dsbenchmark.txchain.TxchainDomWrite;
34 import org.opendaylight.mdsal.binding.api.DataBroker;
35 import org.opendaylight.mdsal.binding.api.RpcProviderService;
36 import org.opendaylight.mdsal.binding.api.WriteTransaction;
37 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
38 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStore;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreOutputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTest;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestOutput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestOutputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestExec;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestExecBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatus;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatus.ExecStatus;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatusBuilder;
52 import org.opendaylight.yangtools.concepts.Registration;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.opendaylight.yangtools.yang.binding.Rpc;
55 import org.opendaylight.yangtools.yang.common.RpcResult;
56 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
57 import org.opendaylight.yangtools.yang.common.Uint32;
58 import org.osgi.service.component.annotations.Activate;
59 import org.osgi.service.component.annotations.Component;
60 import org.osgi.service.component.annotations.Deactivate;
61 import org.osgi.service.component.annotations.Reference;
62 import org.osgi.service.component.annotations.RequireServiceComponentRuntime;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
67 @Component(service = { })
68 @RequireServiceComponentRuntime
69 public final class DsbenchmarkProvider implements AutoCloseable {
70 private static final Logger LOG = LoggerFactory.getLogger(DsbenchmarkProvider.class);
71 private static final InstanceIdentifier<TestExec> TEST_EXEC_IID = InstanceIdentifier.create(TestExec.class);
72 private static final InstanceIdentifier<TestStatus> TEST_STATUS_IID = InstanceIdentifier.create(TestStatus.class);
74 private final AtomicReference<ExecStatus> execStatus = new AtomicReference<>(ExecStatus.Idle);
75 private final DsbenchmarkListenerProvider listenerProvider;
76 // Async DOM Broker for use with all DOM operations
77 private final DOMDataBroker domDataBroker;
78 // Async Binding-Aware Broker for use in tx chains;
79 private final DataBroker dataBroker;
80 private final Registration rpcReg;
82 private long testsCompleted = 0;
86 @SuppressWarnings("checkstyle:illegalCatch")
87 public DsbenchmarkProvider(@Reference final DOMDataBroker domDataBroker, @Reference final DataBroker dataBroker,
88 @Reference final RpcProviderService rpcService) {
89 this.domDataBroker = requireNonNull(domDataBroker);
90 this.dataBroker = requireNonNull(dataBroker);
91 listenerProvider = new DsbenchmarkListenerProvider(dataBroker);
94 // We want to set the initial operation status so users can detect we are ready to start test.
95 setTestOperData(execStatus.get(), testsCompleted);
96 } catch (final Exception e) {
97 // TODO: Use a singleton service to make sure the initial write is performed only once.
98 LOG.warn("Working around Bugs 8829 and 6793 by ignoring exception from setTestOperData", e);
101 rpcReg = rpcService.registerRpcImplementations(ImmutableClassToInstanceMap.<Rpc<?, ?>>builder()
102 .put(StartTest.class, this::startTest)
103 .put(CleanupStore.class, this::cleanupStore)
105 LOG.info("DsbenchmarkProvider initiated");
111 public void close() {
113 LOG.info("DsbenchmarkProvider closed");
116 private ListenableFuture<RpcResult<CleanupStoreOutput>> cleanupStore(final CleanupStoreInput input) {
118 LOG.debug("Data Store cleaned up");
119 return Futures.immediateFuture(RpcResultBuilder.success(new CleanupStoreOutputBuilder().build()).build());
122 @SuppressWarnings("checkstyle:illegalCatch")
123 private ListenableFuture<RpcResult<StartTestOutput>> startTest(final StartTestInput input) {
124 LOG.info("Starting the data store benchmark test, input: {}", input);
126 // Check if there is a test in progress
127 if (!execStatus.compareAndSet(ExecStatus.Idle, ExecStatus.Executing)) {
128 LOG.info("Test in progress");
129 return RpcResultBuilder.success(new StartTestOutputBuilder()
130 .setStatus(StartTestOutput.Status.TESTINPROGRESS)
131 .build()).buildFuture();
134 // Cleanup data that may be left over from a previous test run
137 // Get the appropriate writer based on operation type and data format
138 DatastoreAbstractWriter dsWriter = getDatastoreWriter(input);
140 // Create listeners on OPERATIONAL and CONFIG test data subtrees
141 listenerProvider.createAndRegisterListeners(input.getListeners().intValue());
144 long startTime = System.nanoTime();
145 dsWriter.createList();
146 long endTime = System.nanoTime();
147 final long listCreateTime = (endTime - startTime) / 1000;
149 // Run the test and measure the execution time
152 startTime = System.nanoTime();
153 dsWriter.executeList();
154 endTime = System.nanoTime();
155 execTime = (endTime - startTime) / 1000;
159 } catch (final Exception e) {
160 LOG.error("Test error", e);
161 execStatus.set(ExecStatus.Idle);
162 return RpcResultBuilder.success(new StartTestOutputBuilder()
163 .setStatus(StartTestOutput.Status.FAILED)
164 .build()).buildFuture();
167 LOG.info("Test finished");
168 setTestOperData(ExecStatus.Idle, testsCompleted);
169 execStatus.set(ExecStatus.Idle);
171 // Get the number of data change events and cleanup the data change listeners
172 long numDataChanges = listenerProvider.getDataChangeCount();
173 long numEvents = listenerProvider.getEventCountAndDestroyListeners();
175 StartTestOutput output = new StartTestOutputBuilder()
176 .setStatus(StartTestOutput.Status.OK)
177 .setListBuildTime(listCreateTime)
178 .setExecTime(execTime)
179 .setTxOk(Uint32.valueOf(dsWriter.getTxOk()))
180 .setNtfOk(Uint32.valueOf(numEvents))
181 .setDataChangeEventsOk(Uint32.valueOf(numDataChanges))
182 .setTxError(Uint32.valueOf(dsWriter.getTxError()))
185 return RpcResultBuilder.success(output).buildFuture();
188 private void setTestOperData(final ExecStatus sts, final long tstCompl) {
189 TestStatus status = new TestStatusBuilder()
191 .setTestsCompleted(Uint32.valueOf(tstCompl))
194 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
195 tx.put(LogicalDatastoreType.OPERATIONAL, TEST_STATUS_IID, status);
199 } catch (final InterruptedException | ExecutionException e) {
200 throw new IllegalStateException(e);
203 LOG.debug("DataStore test oper status populated: {}", status);
206 private void cleanupTestStore() {
207 TestExec data = new TestExecBuilder().setOuterList(Collections.emptyMap()).build();
209 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
210 tx.put(LogicalDatastoreType.CONFIGURATION, TEST_EXEC_IID, data);
213 LOG.debug("DataStore config test data cleaned up");
214 } catch (final InterruptedException | ExecutionException e) {
215 LOG.info("Failed to cleanup DataStore configtest data");
216 throw new IllegalStateException(e);
219 tx = dataBroker.newWriteOnlyTransaction();
220 tx.put(LogicalDatastoreType.OPERATIONAL, TEST_EXEC_IID, data);
223 LOG.debug("DataStore operational test data cleaned up");
224 } catch (final InterruptedException | ExecutionException e) {
225 LOG.info("Failed to cleanup DataStore operational test data");
226 throw new IllegalStateException(e);
231 private DatastoreAbstractWriter getDatastoreWriter(final StartTestInput input) {
233 final DatastoreAbstractWriter retVal;
235 StartTestInput.TransactionType txType = input.getTransactionType();
236 StartTestInput.Operation oper = input.getOperation();
237 StartTestInput.DataFormat dataFormat = input.getDataFormat();
238 StartTestInput.DataStore dataStore = input.getDataStore();
239 int outerListElem = input.getOuterElements().intValue();
240 int innerListElem = input.getInnerElements().intValue();
241 int writesPerTx = input.getPutsPerTx().intValue();
244 if (txType == StartTestInput.TransactionType.SIMPLETX) {
245 if (dataFormat == StartTestInput.DataFormat.BINDINGAWARE) {
246 if (StartTestInput.Operation.DELETE == oper) {
247 retVal = new SimpletxBaDelete(dataBroker, outerListElem,
248 innerListElem,writesPerTx, dataStore);
249 } else if (StartTestInput.Operation.READ == oper) {
250 retVal = new SimpletxBaRead(dataBroker, outerListElem,
251 innerListElem, writesPerTx, dataStore);
253 retVal = new SimpletxBaWrite(dataBroker, oper, outerListElem,
254 innerListElem, writesPerTx, dataStore);
256 } else if (StartTestInput.Operation.DELETE == oper) {
257 retVal = new SimpletxDomDelete(domDataBroker, outerListElem,
258 innerListElem, writesPerTx, dataStore);
259 } else if (StartTestInput.Operation.READ == oper) {
260 retVal = new SimpletxDomRead(domDataBroker, outerListElem,
261 innerListElem, writesPerTx, dataStore);
263 retVal = new SimpletxDomWrite(domDataBroker, oper, outerListElem,
264 innerListElem, writesPerTx, dataStore);
266 } else if (dataFormat == StartTestInput.DataFormat.BINDINGAWARE) {
267 if (StartTestInput.Operation.DELETE == oper) {
268 retVal = new TxchainBaDelete(dataBroker, outerListElem,
269 innerListElem, writesPerTx, dataStore);
270 } else if (StartTestInput.Operation.READ == oper) {
271 retVal = new TxchainBaRead(dataBroker, outerListElem,
272 innerListElem,writesPerTx, dataStore);
274 retVal = new TxchainBaWrite(dataBroker, oper, outerListElem,
275 innerListElem, writesPerTx, dataStore);
277 } else if (StartTestInput.Operation.DELETE == oper) {
278 retVal = new TxchainDomDelete(domDataBroker, outerListElem,
279 innerListElem, writesPerTx, dataStore);
280 } else if (StartTestInput.Operation.READ == oper) {
281 retVal = new TxchainDomRead(domDataBroker, outerListElem,
282 innerListElem, writesPerTx, dataStore);
285 retVal = new TxchainDomWrite(domDataBroker, oper, outerListElem,
286 innerListElem,writesPerTx, dataStore);
289 execStatus.set(ExecStatus.Idle);