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

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.