Merge "Dynamically update DatastoreContext properties"
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / TransactionRateLimitingCallback.java
1 /*
2  * Copyright (c) 2015 Cisco 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
9 package org.opendaylight.controller.cluster.datastore;
10
11 import com.codahale.metrics.Snapshot;
12 import com.codahale.metrics.Timer;
13 import com.google.common.base.Preconditions;
14 import java.util.concurrent.TimeUnit;
15 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 /**
20  * TransactionRateLimitingCallback computes the new transaction rate limit on the successful completion of a
21  * transaction
22  */
23 public class TransactionRateLimitingCallback implements OperationCallback{
24
25     private static final Logger LOG = LoggerFactory.getLogger(TransactionRateLimitingCallback.class);
26     private static final String COMMIT = "commit";
27
28     private final Timer commitTimer;
29     private final ActorContext actorContext;
30     private Timer.Context timerContext;
31
32     TransactionRateLimitingCallback(ActorContext actorContext){
33         this.actorContext = actorContext;
34         commitTimer = actorContext.getOperationTimer(COMMIT);
35     }
36
37     @Override
38     public void run() {
39         timerContext = commitTimer.time();
40     }
41
42     @Override
43     public void success() {
44         Preconditions.checkState(timerContext != null, "Call run before success");
45         timerContext.stop();
46
47         Snapshot timerSnapshot = commitTimer.getSnapshot();
48         double newRateLimit = 0;
49
50         long commitTimeoutInSeconds = actorContext.getDatastoreContext()
51                 .getShardTransactionCommitTimeoutInSeconds();
52         long commitTimeoutInNanos = TimeUnit.SECONDS.toNanos(commitTimeoutInSeconds);
53
54         // Find the time that it takes for transactions to get executed in every 10th percentile
55         // Compute the rate limit for that percentile and sum it up
56         for(int i=1;i<=10;i++){
57             // Get the amount of time transactions take in the i*10th percentile
58             double percentileTimeInNanos = timerSnapshot.getValue(i * 0.1D);
59
60             if(percentileTimeInNanos > 0) {
61                 // Figure out the rate limit for the i*10th percentile in nanos
62                 double percentileRateLimit = ((double) commitTimeoutInNanos / percentileTimeInNanos);
63
64                 // Add the percentileRateLimit to the total rate limit
65                 newRateLimit += percentileRateLimit;
66             }
67         }
68
69         // Compute the rate limit per second
70         newRateLimit = newRateLimit/(commitTimeoutInSeconds*10);
71
72         LOG.debug("Data Store {} commit rateLimit adjusted to {}", actorContext.getDataStoreType(), newRateLimit);
73
74         actorContext.setTxCreationLimit(newRateLimit);
75     }
76
77     @Override
78     public void failure() {
79         // This would mean we couldn't get a transaction completed in 30 seconds which is
80         // the default transaction commit timeout. Using the timeout information to figure out the rate limit is
81         // not going to be useful - so we leave it as it is
82     }
83 }