Improve segmented journal actor metrics
[controller.git] / benchmark / dsbenchmark / src / main / java / org / opendaylight / dsbenchmark / DsbenchmarkProvider.java
1 /*
2  * Copyright (c) 2015 Cisco Systems and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.dsbenchmark;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Collections;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.atomic.AtomicReference;
17 import javax.annotation.PreDestroy;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.dsbenchmark.listener.DsbenchmarkListenerProvider;
21 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaDelete;
22 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaRead;
23 import org.opendaylight.dsbenchmark.simpletx.SimpletxBaWrite;
24 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomDelete;
25 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomRead;
26 import org.opendaylight.dsbenchmark.simpletx.SimpletxDomWrite;
27 import org.opendaylight.dsbenchmark.txchain.TxchainBaDelete;
28 import org.opendaylight.dsbenchmark.txchain.TxchainBaRead;
29 import org.opendaylight.dsbenchmark.txchain.TxchainBaWrite;
30 import org.opendaylight.dsbenchmark.txchain.TxchainDomDelete;
31 import org.opendaylight.dsbenchmark.txchain.TxchainDomRead;
32 import org.opendaylight.dsbenchmark.txchain.TxchainDomWrite;
33 import org.opendaylight.mdsal.binding.api.DataBroker;
34 import org.opendaylight.mdsal.binding.api.RpcProviderService;
35 import org.opendaylight.mdsal.binding.api.WriteTransaction;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStore;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.CleanupStoreOutputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTest;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestOutput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.StartTestOutputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestExec;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestExecBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatus;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatus.ExecStatus;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.dsbenchmark.rev150105.TestStatusBuilder;
51 import org.opendaylight.yangtools.concepts.Registration;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.opendaylight.yangtools.yang.common.RpcResult;
54 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
55 import org.opendaylight.yangtools.yang.common.Uint32;
56 import org.osgi.service.component.annotations.Activate;
57 import org.osgi.service.component.annotations.Component;
58 import org.osgi.service.component.annotations.Deactivate;
59 import org.osgi.service.component.annotations.Reference;
60 import org.osgi.service.component.annotations.RequireServiceComponentRuntime;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 @Singleton
65 @Component(service = { })
66 @RequireServiceComponentRuntime
67 public final class DsbenchmarkProvider implements AutoCloseable {
68     private static final Logger LOG = LoggerFactory.getLogger(DsbenchmarkProvider.class);
69     private static final InstanceIdentifier<TestExec> TEST_EXEC_IID = InstanceIdentifier.create(TestExec.class);
70     private static final InstanceIdentifier<TestStatus> TEST_STATUS_IID = InstanceIdentifier.create(TestStatus.class);
71
72     private final AtomicReference<ExecStatus> execStatus = new AtomicReference<>(ExecStatus.Idle);
73     private final DsbenchmarkListenerProvider listenerProvider;
74     // Async DOM Broker for use with all DOM operations
75     private final DOMDataBroker domDataBroker;
76     // Async Binding-Aware Broker for use in tx chains;
77     private final DataBroker dataBroker;
78     private final Registration rpcReg;
79
80     private long testsCompleted = 0;
81
82     @Inject
83     @Activate
84     @SuppressWarnings("checkstyle:illegalCatch")
85     public DsbenchmarkProvider(@Reference final DOMDataBroker domDataBroker, @Reference final DataBroker dataBroker,
86             @Reference final RpcProviderService rpcService) {
87         this.domDataBroker = requireNonNull(domDataBroker);
88         this.dataBroker = requireNonNull(dataBroker);
89         listenerProvider = new DsbenchmarkListenerProvider(dataBroker);
90
91         try {
92             // We want to set the initial operation status so users can detect we are ready to start test.
93             setTestOperData(execStatus.get(), testsCompleted);
94         } catch (final Exception e) {
95             // TODO: Use a singleton service to make sure the initial write is performed only once.
96             LOG.warn("Working around Bugs 8829 and 6793 by ignoring exception from setTestOperData", e);
97         }
98
99         rpcReg = rpcService.registerRpcImplementations((StartTest) this::startTest, (CleanupStore) this::cleanupStore);
100         LOG.info("DsbenchmarkProvider initiated");
101     }
102
103     @Override
104     @PreDestroy
105     @Deactivate
106     public void close() {
107         rpcReg.close();
108         LOG.info("DsbenchmarkProvider closed");
109     }
110
111     private ListenableFuture<RpcResult<CleanupStoreOutput>> cleanupStore(final CleanupStoreInput input) {
112         cleanupTestStore();
113         LOG.debug("Data Store cleaned up");
114         return Futures.immediateFuture(RpcResultBuilder.success(new CleanupStoreOutputBuilder().build()).build());
115     }
116
117     @SuppressWarnings("checkstyle:illegalCatch")
118     private ListenableFuture<RpcResult<StartTestOutput>> startTest(final StartTestInput input) {
119         LOG.info("Starting the data store benchmark test, input: {}", input);
120
121         // Check if there is a test in progress
122         if (!execStatus.compareAndSet(ExecStatus.Idle, ExecStatus.Executing)) {
123             LOG.info("Test in progress");
124             return RpcResultBuilder.success(new StartTestOutputBuilder()
125                 .setStatus(StartTestOutput.Status.TESTINPROGRESS)
126                 .build()).buildFuture();
127         }
128
129         // Cleanup data that may be left over from a previous test run
130         cleanupTestStore();
131
132         // Get the appropriate writer based on operation type and data format
133         DatastoreAbstractWriter dsWriter = getDatastoreWriter(input);
134
135         // Create listeners on OPERATIONAL and CONFIG test data subtrees
136         listenerProvider.createAndRegisterListeners(input.getListeners().intValue());
137
138
139         long startTime = System.nanoTime();
140         dsWriter.createList();
141         long endTime = System.nanoTime();
142         final long listCreateTime = (endTime - startTime) / 1000;
143
144         // Run the test and measure the execution time
145         long execTime;
146         try {
147             startTime = System.nanoTime();
148             dsWriter.executeList();
149             endTime = System.nanoTime();
150             execTime = (endTime - startTime) / 1000;
151
152             testsCompleted++;
153
154         } catch (final Exception e) {
155             LOG.error("Test error", e);
156             execStatus.set(ExecStatus.Idle);
157             return RpcResultBuilder.success(new StartTestOutputBuilder()
158                 .setStatus(StartTestOutput.Status.FAILED)
159                 .build()).buildFuture();
160         }
161
162         LOG.info("Test finished");
163         setTestOperData(ExecStatus.Idle, testsCompleted);
164         execStatus.set(ExecStatus.Idle);
165
166         // Get the number of data change events and cleanup the data change listeners
167         long numDataChanges = listenerProvider.getDataChangeCount();
168         long numEvents = listenerProvider.getEventCountAndDestroyListeners();
169
170         StartTestOutput output = new StartTestOutputBuilder()
171                 .setStatus(StartTestOutput.Status.OK)
172                 .setListBuildTime(listCreateTime)
173                 .setExecTime(execTime)
174                 .setTxOk(Uint32.valueOf(dsWriter.getTxOk()))
175                 .setNtfOk(Uint32.valueOf(numEvents))
176                 .setDataChangeEventsOk(Uint32.valueOf(numDataChanges))
177                 .setTxError(Uint32.valueOf(dsWriter.getTxError()))
178                 .build();
179
180         return RpcResultBuilder.success(output).buildFuture();
181     }
182
183     private void setTestOperData(final ExecStatus sts, final long tstCompl) {
184         TestStatus status = new TestStatusBuilder()
185                 .setExecStatus(sts)
186                 .setTestsCompleted(Uint32.valueOf(tstCompl))
187                 .build();
188
189         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
190         tx.put(LogicalDatastoreType.OPERATIONAL, TEST_STATUS_IID, status);
191
192         try {
193             tx.commit().get();
194         } catch (final InterruptedException | ExecutionException e) {
195             throw new IllegalStateException(e);
196         }
197
198         LOG.debug("DataStore test oper status populated: {}", status);
199     }
200
201     private void cleanupTestStore() {
202         TestExec data = new TestExecBuilder().setOuterList(Collections.emptyMap()).build();
203
204         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
205         tx.put(LogicalDatastoreType.CONFIGURATION, TEST_EXEC_IID, data);
206         try {
207             tx.commit().get();
208             LOG.debug("DataStore config test data cleaned up");
209         } catch (final InterruptedException | ExecutionException e) {
210             LOG.info("Failed to cleanup DataStore configtest data");
211             throw new IllegalStateException(e);
212         }
213
214         tx = dataBroker.newWriteOnlyTransaction();
215         tx.put(LogicalDatastoreType.OPERATIONAL, TEST_EXEC_IID, data);
216         try {
217             tx.commit().get();
218             LOG.debug("DataStore operational test data cleaned up");
219         } catch (final InterruptedException | ExecutionException e) {
220             LOG.info("Failed to cleanup DataStore operational test data");
221             throw new IllegalStateException(e);
222         }
223
224     }
225
226     private DatastoreAbstractWriter getDatastoreWriter(final StartTestInput input) {
227
228         final DatastoreAbstractWriter retVal;
229
230         StartTestInput.TransactionType txType = input.getTransactionType();
231         StartTestInput.Operation oper = input.getOperation();
232         StartTestInput.DataFormat dataFormat = input.getDataFormat();
233         StartTestInput.DataStore dataStore = input.getDataStore();
234         int outerListElem = input.getOuterElements().intValue();
235         int innerListElem = input.getInnerElements().intValue();
236         int writesPerTx = input.getPutsPerTx().intValue();
237
238         try {
239             if (txType == StartTestInput.TransactionType.SIMPLETX) {
240                 if (dataFormat == StartTestInput.DataFormat.BINDINGAWARE) {
241                     if (StartTestInput.Operation.DELETE == oper) {
242                         retVal = new SimpletxBaDelete(dataBroker, outerListElem,
243                                 innerListElem,writesPerTx, dataStore);
244                     } else if (StartTestInput.Operation.READ == oper) {
245                         retVal = new SimpletxBaRead(dataBroker, outerListElem,
246                                 innerListElem, writesPerTx, dataStore);
247                     } else {
248                         retVal = new SimpletxBaWrite(dataBroker, oper, outerListElem,
249                                 innerListElem, writesPerTx, dataStore);
250                     }
251                 } else if (StartTestInput.Operation.DELETE == oper) {
252                     retVal = new SimpletxDomDelete(domDataBroker, outerListElem,
253                             innerListElem, writesPerTx, dataStore);
254                 } else if (StartTestInput.Operation.READ == oper) {
255                     retVal = new SimpletxDomRead(domDataBroker, outerListElem,
256                             innerListElem, writesPerTx, dataStore);
257                 } else {
258                     retVal = new SimpletxDomWrite(domDataBroker, oper, outerListElem,
259                             innerListElem, writesPerTx, dataStore);
260                 }
261             } else if (dataFormat == StartTestInput.DataFormat.BINDINGAWARE) {
262                 if (StartTestInput.Operation.DELETE == oper) {
263                     retVal = new TxchainBaDelete(dataBroker, outerListElem,
264                             innerListElem, writesPerTx, dataStore);
265                 } else if (StartTestInput.Operation.READ == oper) {
266                     retVal = new TxchainBaRead(dataBroker, outerListElem,
267                             innerListElem,writesPerTx, dataStore);
268                 } else {
269                     retVal = new TxchainBaWrite(dataBroker, oper, outerListElem,
270                             innerListElem, writesPerTx, dataStore);
271                 }
272             } else if (StartTestInput.Operation.DELETE == oper) {
273                 retVal = new TxchainDomDelete(domDataBroker, outerListElem,
274                         innerListElem, writesPerTx, dataStore);
275             } else if (StartTestInput.Operation.READ == oper) {
276                 retVal = new TxchainDomRead(domDataBroker, outerListElem,
277                         innerListElem, writesPerTx, dataStore);
278
279             } else {
280                 retVal = new TxchainDomWrite(domDataBroker, oper, outerListElem,
281                         innerListElem,writesPerTx, dataStore);
282             }
283         } finally {
284             execStatus.set(ExecStatus.Idle);
285         }
286         return retVal;
287     }
288 }