/*
* Copyright (c) 2017 Ericsson Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.applications.bulk.o.matic;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TableWriter implements FlowCounterMBean {
private final Logger LOG = LoggerFactory.getLogger(TableWriter.class);
private final AtomicInteger writeOpStatus = new AtomicInteger(FlowCounter.OperationStatus.INIT.status());
private final AtomicLong taskCompletionTime = new AtomicLong(BulkOMaticUtils.DEFAULT_COMPLETION_TIME);
private final AtomicInteger successfulWrites = new AtomicInteger();
private final AtomicInteger failedWrites = new AtomicInteger();
private final DataBroker dataBroker;
private final ExecutorService tablePusher;
public TableWriter(final DataBroker dataBroker, final ExecutorService tablePusher) {
this.dataBroker = dataBroker;
this.tablePusher = tablePusher;
}
public void addTables(final int dpnCount, final short startTableId, final short endTableId) {
LOG.info("Starting to add tables: {} to {} on each of {}", startTableId, endTableId, dpnCount);
TableHandlerTask task = new TableHandlerTask(dpnCount, startTableId, endTableId, true);
tablePusher.execute(task);
}
public void deleteTables(int dpnCount, short startTableId, short endTableId) {
LOG.info("Starting to delete tables: {} to {} on each of {}", startTableId, endTableId, dpnCount);
TableHandlerTask task = new TableHandlerTask(dpnCount, startTableId, endTableId, false);
tablePusher.execute(task);
}
@Override
public int getWriteOpStatus() {
return writeOpStatus.get();
}
@Override
public long getTaskCompletionTime() {
return taskCompletionTime.get();
}
@Override
public long getTableCount() {
return successfulWrites.get();
}
private class TableHandlerTask implements Runnable {
private short startTableId;
private short endTableId;
private int dpnCount;
private boolean isAdd;
public TableHandlerTask(int dpnCount, short startTableId, short endTableId, boolean isAdd) {
this.dpnCount = dpnCount;
this.startTableId = startTableId;
this.endTableId = endTableId;
this.isAdd = isAdd;
}
@Override
public void run() {
writeOpStatus.set(FlowCounter.OperationStatus.IN_PROGRESS.status());
int totalTables = dpnCount * (endTableId - startTableId + 1);
for (int dpn = 1; dpn <= dpnCount; dpn++) {
String dpId = BulkOMaticUtils.DEVICE_TYPE_PREFIX + String.valueOf(dpn);
for (short tableId = startTableId; tableId <= endTableId; tableId++) {
WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
Table table = new TableBuilder().setKey(new TableKey(tableId))
.setId(tableId)
.build();
InstanceIdentifier<Table> tableIId = BulkOMaticUtils.getTableId(tableId, dpId);
if (isAdd) {
wtx.put(LogicalDatastoreType.CONFIGURATION, tableIId, table, true);
} else {
wtx.delete(LogicalDatastoreType.CONFIGURATION, tableIId);
}
CheckedFuture<Void, TransactionCommitFailedException> future = wtx.submit();
Futures.addCallback(future, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void v) {
if (successfulWrites.incrementAndGet() == totalTables) {
if (failedWrites.get() > 0) {
writeOpStatus.set(FlowCounter.OperationStatus.FAILURE.status());
} else {
writeOpStatus.set(FlowCounter.OperationStatus.SUCCESS.status());
}
}
}
@Override
public void onFailure(Throwable throwable) {
LOG.error("Table addition Failed. Error: {}", throwable);
if (failedWrites.incrementAndGet() == totalTables) {
writeOpStatus.set(FlowCounter.OperationStatus.FAILURE.status());
}
}
});
}
}
}
}
}