aad65272e4f3c74e8f92a7b8a87492eea84240f2
[ovsdb.git] / southbound / southbound-impl / src / main / java / org / opendaylight / ovsdb / southbound / reconciliation / ReconciliationManager.java
1 /*
2  * Copyright (c) 2016 Brocade Communications Systems, Inc. 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.ovsdb.southbound.reconciliation;
9
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import java.util.concurrent.*;
17
18 /**
19  * This class provides the implementation of ovsdb southbound plugins
20  * configuration reconciliation engine. This engine provide interfaces
21  * to enqueue (one time retry)/ enqueueForRetry(periodic retry)/ dequeue
22  * (remove from retry queue) reconciliation task. Reconciliation task can
23  * be a connection reconciliation or configuration reconciliation of any
24  * ovsdb managed resource like bridge, termination point etc. This engine
25  * execute all the reconciliation task through a fixed size thread pool.
26  * If submitted task need to be retry after a periodic interval they are
27  * submitted to a single thread executor to periodically wake up and check
28  * if task is ready for execution.
29  * Ideally, addition of any type of reconciliation task should not require
30  * any change in this reconciliation manager execution engine.
31  *
32  * 3-Node Cluster:
33  * Reconciliation manager is agnostic of whether it's running in single
34  * node cluster or 3-node cluster. It's a responsibility of the task
35  * submitter to make sure that it submit the task for reconciliation only
36  * if it's an owner of that device EXCEPT controller initiated Connection.
37  * Reconciliation of controller initiated connection should be done by all
38  * the 3-nodes in the cluster, because connection to individual controller
39  * can be interrupted for various reason.
40  *
41  * Created by Anil Vishnoi (avishnoi@Brocade.com) on 3/9/16.
42  */
43 public class ReconciliationManager implements AutoCloseable {
44     private static final Logger LOG = LoggerFactory.getLogger(ReconciliationManager.class);
45
46     private static final int NO_OF_RECONCILER = 10;
47     private static final int RECON_TASK_QUEUE_SIZE = 5000;
48
49     private final DataBroker db;
50     private final ExecutorService reconcilers;
51     private final ScheduledExecutorService taskTriager;
52
53     private final ReconciliationTaskManager reconTaskManager = new ReconciliationTaskManager();
54
55     public ReconciliationManager(final DataBroker db) {
56         this.db = db;
57         reconcilers = SpecialExecutors.newBoundedCachedThreadPool(NO_OF_RECONCILER, RECON_TASK_QUEUE_SIZE, "ovsdb-reconciler");
58
59         ThreadFactory threadFact = new ThreadFactoryBuilder()
60                 .setNameFormat("ovsdb-recon-task-triager-%d").build();
61         taskTriager = Executors.newSingleThreadScheduledExecutor(threadFact);
62     }
63
64     public boolean isEnqueued(final ReconciliationTask task) {
65         return reconTaskManager.isTaskQueued(task);
66     }
67
68     public void enqueue(final ReconciliationTask task) {
69         LOG.trace("Reconciliation task submitted for execution {}",task);
70         reconTaskManager.cacheTask(task, reconcilers.submit(task));
71     }
72
73     public void enqueueForRetry(final ReconciliationTask task) {
74         LOG.trace("Reconciliation task re-queued for re-execution {}",task);
75         reconTaskManager.cacheTask(task, taskTriager.schedule(
76                 new Runnable() {
77                     @Override
78                     public void run() {
79                         task.checkReadinessAndProcess();
80                     }
81                 }, task.retryDelayInMills(), TimeUnit.MILLISECONDS
82             )
83         );
84     }
85
86     public void dequeue(final ReconciliationTask task) {
87         reconTaskManager.cancelTask(task);
88     }
89
90     public DataBroker getDb() {
91         return db;
92     }
93
94     @Override
95     public void close() throws Exception {
96         if (this.reconcilers != null) {
97             this.reconcilers.shutdownNow();
98         }
99
100         if (this.taskTriager != null) {
101             this.taskTriager.shutdownNow();
102         }
103     }
104 }