]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Squashed 'src/dmclock/' changes from a9e777f08f..93f760c57c
authorJ. Eric Ivancich <ivancich@redhat.com>
Wed, 27 Sep 2017 17:37:50 +0000 (13:37 -0400)
committerJ. Eric Ivancich <ivancich@redhat.com>
Wed, 27 Sep 2017 17:37:50 +0000 (13:37 -0400)
93f760c57c Merge pull request #40 from ivancich/wip-change-client-rec-init
824d92dd3d Merge pull request #38 from ivancich/wip-improve-next-request-return
941d1bef54 Change initialization of IndIntruHeapData to C++'s value-initialization to better future-proof the code. Since at the momeent they are scalars they'll be zero-initialized (i.e., to zero). However if they ever become something more complex, their default constructors will be called.
19153d979f Merge pull request #39 from ivancich/wip-delta-rho-plugin
a94c4e086c Allow the calculations of rho and delta to be handled by a "tracker" specified via template parameter (i.e., by static polymorphism). The tracker follows a simple interface constisting of three functions and one static function.
856a26c466 Clarify code surrounding the return value of do_next_request.
b632cfda4f Merge pull request #37 from ivancich/wip-fix-uninit-data
e6df585153 The coverity scan published in ceph-devel on 2017-09-21 revealed some uninitialized data in a constructor. This fixes that.
165a02542d Merge pull request #34 from TaewoongKim/anticipate
72e4df95cf Make anticipation_timeout configurable with config file
2f06d632d5 Add anticipation duration that keeps from resetting tag values to the current time

git-subtree-dir: src/dmclock
git-subtree-split: 93f760c57c75b9eb88382bcba29fcac3ce365e7f

sim/src/config.cc
sim/src/config.h
sim/src/test_dmclock.h
sim/src/test_dmclock_main.cc
src/dmclock_client.h
src/dmclock_server.h
test/test_dmclock_client.cc

index a6702897cd6f759e59ca54d3a1d55f32f3b5ed51..a55ba9a47bcc95bfb903b14fd61fbf0eb007121f 100644 (file)
@@ -130,6 +130,8 @@ int crimson::qos_simulation::parse_config_file(const std::string &fname, sim_con
     g_conf.server_random_selection = stobool(val);
   if (!cf.read("global", "server_soft_limit", val))
     g_conf.server_soft_limit = stobool(val);
+  if (!cf.read("global", "anticipation_timeout", val))
+    g_conf.anticipation_timeout = stod(val);
 
   for (uint i = 0; i < g_conf.server_groups; i++) {
     srv_group_t st;
index 010f33a743ea4d1e38987b2564589d4dadbdab76..e85c69d0745138d66f4af2100acdb8e982b29749 100644 (file)
@@ -100,6 +100,7 @@ namespace crimson {
       uint client_groups;
       bool server_random_selection;
       bool server_soft_limit;
+      double anticipation_timeout;
 
       std::vector<cli_group_t> cli_group;
       std::vector<srv_group_t> srv_group;
@@ -107,11 +108,13 @@ namespace crimson {
       sim_config_t(uint _server_groups = 1,
                   uint _client_groups = 1,
                   bool _server_random_selection = false,
-                  bool _server_soft_limit = true) :
+                  bool _server_soft_limit = true,
+                  double _anticipation_timeout = 0.0) :
        server_groups(_server_groups),
        client_groups(_client_groups),
        server_random_selection(_server_random_selection),
-       server_soft_limit(_server_soft_limit)
+       server_soft_limit(_server_soft_limit),
+       anticipation_timeout(_anticipation_timeout)
       {
        srv_group.reserve(server_groups);
        cli_group.reserve(client_groups);
@@ -123,7 +126,9 @@ namespace crimson {
          "server_groups = " << sim_config.server_groups << "\n" <<
          "client_groups = " << sim_config.client_groups << "\n" <<
          "server_random_selection = " << sim_config.server_random_selection << "\n" <<
-         "server_soft_limit = " << sim_config.server_soft_limit;
+         "server_soft_limit = " << sim_config.server_soft_limit << "\n" <<
+         std::fixed << std::setprecision(3) << 
+         "anticipation_timeout = " << sim_config.anticipation_timeout;
        return out;
       }
     }; // class sim_config_t
index 7f1e55439edc2732c844faf11482b40a8d7f9560..9728b45f935aacb1e249a1c0337a748bcd8e9470 100644 (file)
@@ -29,13 +29,14 @@ namespace crimson {
     };
 
     using DmcQueue = dmc::PushPriorityQueue<ClientId,sim::TestRequest>;
+    using DmcServiceTracker = dmc::ServiceTracker<ServerId,dmc::BorrowingTracker>;
 
     using DmcServer = sim::SimulatedServer<DmcQueue,
                                           dmc::ReqParams,
                                           dmc::PhaseType,
                                           DmcAccum>;
 
-    using DmcClient = sim::SimulatedClient<dmc::ServiceTracker<ServerId>,
+    using DmcClient = sim::SimulatedClient<DmcServiceTracker,
                                           dmc::ReqParams,
                                           dmc::PhaseType,
                                           DmcAccum>;
index 57b733e860cede4065a36d2ad2034450c35f8399..f59b735465ba20f13f2ecb82a110e7e74fe1d87e 100644 (file)
@@ -74,6 +74,7 @@ int main(int argc, char* argv[]) {
     const uint client_groups = g_conf.client_groups;
     const bool server_random_selection = g_conf.server_random_selection;
     const bool server_soft_limit = g_conf.server_soft_limit;
+    const double anticipation_timeout = g_conf.anticipation_timeout;
     uint server_total_count = 0;
     uint client_total_count = 0;
 
@@ -176,7 +177,11 @@ int main(int argc, char* argv[]) {
     test::CreateQueueF create_queue_f =
         [&](test::DmcQueue::CanHandleRequestFunc can_f,
             test::DmcQueue::HandleRequestFunc handle_f) -> test::DmcQueue* {
-        return new test::DmcQueue(client_info_f, can_f, handle_f, server_soft_limit);
+        return new test::DmcQueue(client_info_f,
+                                  can_f,
+                                  handle_f,
+                                  server_soft_limit,
+                                  anticipation_timeout);
     };
 
  
@@ -232,9 +237,9 @@ int main(int argc, char* argv[]) {
 
 
 void test::client_data(std::ostream& out,
-                test::MySim* sim,
-                test::MySim::ClientFilter client_disp_filter,
-                int head_w, int data_w, int data_prec) {
+                      test::MySim* sim,
+                      test::MySim::ClientFilter client_disp_filter,
+                      int head_w, int data_w, int data_prec) {
     // report how many ops were done by reservation and proportion for
     // each client
 
@@ -265,9 +270,9 @@ void test::client_data(std::ostream& out,
 
 
 void test::server_data(std::ostream& out,
-                test::MySim* sim,
-                test::MySim::ServerFilter server_disp_filter,
-                int head_w, int data_w, int data_prec) {
+                      test::MySim* sim,
+                      test::MySim::ServerFilter server_disp_filter,
+                      int head_w, int data_w, int data_prec) {
     out << std::setw(head_w) << "res_ops:";
     int total_r = 0;
     for (uint i = 0; i < sim->get_server_count(); ++i) {
index 92f4cf83bb1abbdad5c792b5377258f9227dd653..e0280ab311c1f62eb466fdb1af012f79f95bc74b 100644 (file)
 
 namespace crimson {
   namespace dmclock {
-    struct ServerInfo {
+
+    // OrigTracker is a best-effort implementation of the the original
+    // dmClock calculations of delta and rho. It adheres to an
+    // interface, implemented via a template type, that allows it to
+    // be replaced with an alternative. The interface consists of the
+    // static create, prepare_req, resp_update, and get_last_delta
+    // functions.
+    class OrigTracker {
       Counter   delta_prev_req;
       Counter   rho_prev_req;
       uint32_t  my_delta;
       uint32_t  my_rho;
 
-      ServerInfo(Counter _delta_prev_req,
-                Counter _rho_prev_req) :
-       delta_prev_req(_delta_prev_req),
-       rho_prev_req(_rho_prev_req),
+    public:
+
+      OrigTracker(Counter global_delta,
+                Counter global_rho) :
+       delta_prev_req(global_delta),
+       rho_prev_req(global_rho),
        my_delta(0),
        my_rho(0)
-      {
-       // empty
+      { /* empty */ }
+
+      static inline OrigTracker create(Counter the_delta, Counter the_rho) {
+       return OrigTracker(the_delta, the_rho);
       }
 
-      inline void req_update(Counter delta, Counter rho) {
-       delta_prev_req = delta;
-       rho_prev_req = rho;
+      inline ReqParams prepare_req(Counter& the_delta, Counter& the_rho) {
+       Counter delta_out = 1 + the_delta - delta_prev_req - my_delta;
+       Counter rho_out = 1 + the_rho - rho_prev_req - my_rho;
+       delta_prev_req = the_delta;
+       rho_prev_req = the_rho;
        my_delta = 0;
        my_rho = 0;
+       return ReqParams(uint32_t(delta_out), uint32_t(rho_out));
       }
 
-      inline void resp_update(PhaseType phase) {
+      inline void resp_update(PhaseType phase,
+                             Counter& the_delta,
+                             Counter& the_rho) {
+       ++the_delta;
        ++my_delta;
-       if (phase == PhaseType::reservation) ++my_rho;
+       if (phase == PhaseType::reservation) {
+         ++the_rho;
+         ++my_rho;
+       }
+      }
+
+      inline Counter get_last_delta() const {
+       return delta_prev_req;
       }
-    };
+    }; // struct OrigTracker
+
+
+    // BorrowingTracker always returns a positive delta and rho. If
+    // not enough responses have come in to allow that, we will borrow
+    // a future response and repay it later.
+    class BorrowingTracker {
+      Counter delta_prev_req;
+      Counter rho_prev_req;
+      Counter delta_borrow;
+      Counter rho_borrow;
+
+    public:
+
+      BorrowingTracker(Counter global_delta, Counter global_rho) :
+       delta_prev_req(global_delta),
+       rho_prev_req(global_rho),
+       delta_borrow(0),
+       rho_borrow(0)
+      { /* empty */ }
+
+      static inline BorrowingTracker create(Counter the_delta,
+                                           Counter the_rho) {
+       return BorrowingTracker(the_delta, the_rho);
+      }
+
+      inline Counter calc_with_borrow(const Counter& global,
+                                     const Counter& previous,
+                                     Counter& borrow) {
+       Counter result = global - previous;
+       if (0 == result) {
+         // if no replies have come in, borrow one from the future
+         ++borrow;
+         return 1;
+       } else if (result > borrow) {
+         // if we can give back all of what we borrowed, do so
+         result -= borrow;
+         borrow = 0;
+         return result;
+       } else {
+         // can only return part of what was borrowed in order to
+         // return positive
+         borrow = borrow - result + 1;
+         return 1;
+       }
+      }
+
+      inline ReqParams prepare_req(Counter& the_delta, Counter& the_rho) {
+       Counter delta_out =
+         calc_with_borrow(the_delta, delta_prev_req, delta_borrow);
+       Counter rho_out =
+         calc_with_borrow(the_rho, rho_prev_req, rho_borrow);
+       delta_prev_req = the_delta;
+       rho_prev_req = the_rho;
+       return ReqParams(uint32_t(delta_out), uint32_t(rho_out));
+      }
+
+      inline void resp_update(PhaseType phase,
+                             Counter& the_delta,
+                             Counter& the_rho) {
+       ++the_delta;
+       if (phase == PhaseType::reservation) {
+         ++the_rho;
+       }
+      }
+
+      inline Counter get_last_delta() const {
+       return delta_prev_req;
+      }
+    }; // struct BorrowingTracker
 
 
     // S is server identifier type
-    template<typename S>
+    // T is the server info class that adheres to ServerTrackerIfc interface
+    template<typename S, typename T = BorrowingTracker>
     class ServiceTracker {
       // we don't want to include gtest.h just for FRIEND_TEST
       friend class dmclock_client_server_erase_Test;
@@ -64,7 +158,7 @@ namespace crimson {
 
       Counter                 delta_counter; // # reqs completed
       Counter                 rho_counter;   // # reqs completed via reservation
-      std::map<S,ServerInfo>  server_map;
+      std::map<S,T>           server_map;
       mutable std::mutex      data_mtx;      // protects Counters and map
 
       using DataGuard = std::lock_guard<decltype(data_mtx)>;
@@ -72,7 +166,7 @@ namespace crimson {
       // clean config
 
       std::deque<MarkPoint>     clean_mark_points;
-      Duration                  clean_age;     // age at which ServerInfo cleaned
+      Duration                  clean_age;     // age at which server tracker cleaned
 
       // NB: All threads declared at end, so they're destructed firs!
 
@@ -119,20 +213,13 @@ namespace crimson {
          // this code can only run if a request did not precede the
          // response or if the record was cleaned up b/w when
          // the request was made and now
-         ServerInfo si(delta_counter, rho_counter);
-         si.resp_update(phase);
-         server_map.emplace(server_id, si);
-       } else {
-         it->second.resp_update(phase);
-       }
-
-       ++delta_counter;
-       if (PhaseType::reservation == phase) {
-         ++rho_counter;
+         auto i = server_map.emplace(server_id,
+                                     T::create(delta_counter, rho_counter));
+         it = i.first;
        }
+       it->second.resp_update(phase, delta_counter, rho_counter);
       }
 
-
       /*
        * Returns the ReqParams for the given server.
        */
@@ -140,17 +227,11 @@ namespace crimson {
        DataGuard g(data_mtx);
        auto it = server_map.find(server);
        if (server_map.end() == it) {
-         server_map.emplace(server, ServerInfo(delta_counter, rho_counter));
+         server_map.emplace(server,
+                            T::create(delta_counter, rho_counter));
          return ReqParams(1, 1);
        } else {
-         Counter delta =
-           1 + delta_counter - it->second.delta_prev_req - it->second.my_delta;
-         Counter rho =
-           1 + rho_counter - it->second.rho_prev_req - it->second.my_rho;
-
-         it->second.req_update(delta_counter, rho_counter);
-
-         return ReqParams(uint32_t(delta), uint32_t(rho));
+         return it->second.prepare_req(delta_counter, rho_counter);
        }
       }
 
@@ -182,7 +263,7 @@ namespace crimson {
               i != server_map.end();
               /* empty */) {
            auto i2 = i++;
-           if (i2->second.delta_prev_req <= earliest) {
+           if (i2->second.get_last_delta() <= earliest) {
              server_map.erase(i2);
            }
          }
index aac848746c0cae3ef790cd9b3ed5b607d2486b0d..8f0e1925e05c3ae084860ea41d60d3143441299b 100644 (file)
@@ -109,36 +109,38 @@ namespace crimson {
       double proportion;
       double limit;
       bool   ready; // true when within limit
-#ifndef DO_NOT_DELAY_TAG_CALC
       Time   arrival;
-#endif
 
       RequestTag(const RequestTag& prev_tag,
                 const ClientInfo& client,
                 const uint32_t delta,
                 const uint32_t rho,
                 const Time time,
-                const double cost = 0.0) :
-       reservation(cost + tag_calc(time,
-                                   prev_tag.reservation,
-                                   client.reservation_inv,
-                                   rho,
-                                   true)),
-       proportion(tag_calc(time,
-                           prev_tag.proportion,
-                           client.weight_inv,
-                           delta,
-                           true)),
-       limit(tag_calc(time,
-                      prev_tag.limit,
-                      client.limit_inv,
-                      delta,
-                      false)),
-       ready(false)
-#ifndef DO_NOT_DELAY_TAG_CALC
-       , arrival(time)
-#endif
+                const double cost = 0.0,
+                const double anticipation_timeout = 0.0) :
+       ready(false),
+       arrival(time)
       {
+       Time max_time = time;
+       if (time - anticipation_timeout < prev_tag.arrival)
+         max_time -= anticipation_timeout;
+       
+       reservation = cost + tag_calc(max_time,
+                                     prev_tag.reservation,
+                                     client.reservation_inv,
+                                     rho,
+                                     true);
+       proportion = tag_calc(max_time,
+                             prev_tag.proportion,
+                             client.weight_inv,
+                             delta,
+                             true);
+       limit = tag_calc(max_time,
+                        prev_tag.limit,
+                        client.limit_inv,
+                        delta,
+                        false);
+
        assert(reservation < max_tag || proportion < max_tag);
       }
 
@@ -146,18 +148,18 @@ namespace crimson {
                 const ClientInfo& client,
                 const ReqParams req_params,
                 const Time time,
-                const double cost = 0.0) :
-       RequestTag(prev_tag, client, req_params.delta, req_params.rho, time, cost)
+                const double cost = 0.0,
+                const double anticipation_timeout = 0.0) :
+       RequestTag(prev_tag, client, req_params.delta, req_params.rho, time,
+                  cost, anticipation_timeout)
       { /* empty */ }
 
       RequestTag(double _res, double _prop, double _lim, const Time _arrival) :
        reservation(_res),
        proportion(_prop),
        limit(_lim),
-       ready(false)
-#ifndef DO_NOT_DELAY_TAG_CALC
-       , arrival(_arrival)
-#endif
+       ready(false),
+       arrival(_arrival)
       {
        assert(reservation < max_tag || proportion < max_tag);
       }
@@ -166,10 +168,8 @@ namespace crimson {
        reservation(other.reservation),
        proportion(other.proportion),
        limit(other.limit),
-       ready(other.ready)
-#ifndef DO_NOT_DELAY_TAG_CALC
-       , arrival(other.arrival)
-#endif
+       ready(other.ready),
+       arrival(other.arrival)
       {
        // empty
       }
@@ -296,11 +296,11 @@ namespace crimson {
        // an idle client becoming unidle
        double                prop_delta = 0.0;
 
-       c::IndIntruHeapData   reserv_heap_data;
-       c::IndIntruHeapData   lim_heap_data;
-       c::IndIntruHeapData   ready_heap_data;
+       c::IndIntruHeapData   reserv_heap_data {};
+       c::IndIntruHeapData   lim_heap_data {};
+       c::IndIntruHeapData   ready_heap_data {};
 #if USE_PROP_HEAP
-       c::IndIntruHeapData   prop_heap_data;
+       c::IndIntruHeapData   prop_heap_data {};
 #endif
 
       public:
@@ -340,6 +340,7 @@ namespace crimson {
          assign_unpinned_tag(prev_tag.reservation, _prev.reservation);
          assign_unpinned_tag(prev_tag.limit, _prev.limit);
          assign_unpinned_tag(prev_tag.proportion, _prev.proportion);
+         prev_tag.arrival = _prev.arrival;
          last_tick = _tick;
        }
 
@@ -449,6 +450,26 @@ namespace crimson {
          HeapId    heap_id;
          Time      when_ready;
        };
+
+       inline explicit NextReq() :
+         type(NextReqType::none)
+       { }
+
+       inline NextReq(HeapId _heap_id) :
+         type(NextReqType::returning),
+         heap_id(_heap_id)
+       { }
+
+       inline NextReq(Time _when_ready) :
+         type(NextReqType::future),
+         when_ready(_when_ready)
+       { }
+
+       // calls to this are clearer than calls to the default
+       // constructor
+       static inline NextReq none() {
+         return NextReq();
+       }
       };
 
 
@@ -714,6 +735,7 @@ namespace crimson {
       // limit, this will allow the request next in terms of
       // proportion to still get issued
       bool             allow_limit_break;
+      double           anticipation_timeout;
 
       std::atomic_bool finishing;
 
@@ -742,9 +764,11 @@ namespace crimson {
                        std::chrono::duration<Rep,Per> _idle_age,
                        std::chrono::duration<Rep,Per> _erase_age,
                        std::chrono::duration<Rep,Per> _check_time,
-                       bool _allow_limit_break) :
+                       bool _allow_limit_break,
+                       double _anticipation_timeout) :
        client_info_f(_client_info_f),
        allow_limit_break(_allow_limit_break),
+       anticipation_timeout(_anticipation_timeout),
        finishing(false),
        idle_age(std::chrono::duration_cast<Duration>(_idle_age)),
        erase_age(std::chrono::duration_cast<Duration>(_erase_age)),
@@ -862,13 +886,20 @@ namespace crimson {
                           get_cli_info(client),
                           req_params,
                           time,
-                          cost);
+                          cost,
+                           anticipation_timeout);
 
          // copy tag to previous tag for client
          client.update_req_tag(tag, tick);
        }
 #else
-       RequestTag tag(client.get_req_tag(), get_cli_info(client), req_params, time, cost);
+       RequestTag tag(client.get_req_tag(),
+                      get_cli_info(client),
+                      req_params,
+                      time,
+                      cost,
+                      anticipation_timeout);
+
        // copy tag to previous tag for client
        client.update_req_tag(tag, tick);
 #endif
@@ -920,7 +951,8 @@ namespace crimson {
          ClientReq& next_first = top.next_request();
          next_first.tag = RequestTag(tag, get_cli_info(top),
                                      top.cur_delta, top.cur_rho,
-                                     next_first.tag.arrival);
+                                     next_first.tag.arrival,
+                                      0.0, anticipation_timeout);
 
          // copy tag to previous tag for client
          top.update_req_tag(next_first.tag, tick);
@@ -968,12 +1000,10 @@ namespace crimson {
 
       // data_mtx should be held when called
       NextReq do_next_request(Time now) {
-       NextReq result{};
-
-       // if reservation queue is empty, all are empty (i.e., no active clients)
+       // if reservation queue is empty, all are empty (i.e., no
+       // active clients)
        if(resv_heap.empty()) {
-         result.type = NextReqType::none;
-         return result;
+         return NextReq::none();
        }
 
        // try constraint (reservation) based scheduling
@@ -981,9 +1011,7 @@ namespace crimson {
        auto& reserv = resv_heap.top();
        if (reserv.has_request() &&
            reserv.next_request().tag.reservation <= now) {
-         result.type = NextReqType::returning;
-         result.heap_id = HeapId::reservation;
-         return result;
+         return NextReq(HeapId::reservation);
        }
 
        // no existing reservations before now, so try weight-based
@@ -1006,9 +1034,7 @@ namespace crimson {
        if (readys.has_request() &&
            readys.next_request().tag.ready &&
            readys.next_request().tag.proportion < max_tag) {
-         result.type = NextReqType::returning;
-         result.heap_id = HeapId::ready;
-         return result;
+         return NextReq(HeapId::ready);
        }
 
        // if nothing is schedulable by reservation or
@@ -1018,14 +1044,10 @@ namespace crimson {
        if (allow_limit_break) {
          if (readys.has_request() &&
              readys.next_request().tag.proportion < max_tag) {
-           result.type = NextReqType::returning;
-           result.heap_id = HeapId::ready;
-           return result;
+           return NextReq(HeapId::ready);
          } else if (reserv.has_request() &&
                     reserv.next_request().tag.reservation < max_tag) {
-           result.type = NextReqType::returning;
-           result.heap_id = HeapId::reservation;
-           return result;
+           return NextReq(HeapId::reservation);
          }
        }
 
@@ -1044,12 +1066,9 @@ namespace crimson {
          next_call = min_not_0_time(next_call, next.tag.limit);
        }
        if (next_call < TimeMax) {
-         result.type = NextReqType::future;
-         result.when_ready = next_call;
-         return result;
+         return NextReq(next_call);
        } else {
-         result.type = NextReqType::none;
-         return result;
+         return NextReq::none();
        }
       } // do_next_request
 
@@ -1169,10 +1188,11 @@ namespace crimson {
                        std::chrono::duration<Rep,Per> _idle_age,
                        std::chrono::duration<Rep,Per> _erase_age,
                        std::chrono::duration<Rep,Per> _check_time,
-                       bool _allow_limit_break = false) :
+                       bool _allow_limit_break = false,
+                       double _anticipation_timeout = 0.0) :
        super(_client_info_f,
              _idle_age, _erase_age, _check_time,
-             _allow_limit_break)
+             _allow_limit_break, _anticipation_timeout)
       {
        // empty
       }
@@ -1393,10 +1413,11 @@ namespace crimson {
                        std::chrono::duration<Rep,Per> _idle_age,
                        std::chrono::duration<Rep,Per> _erase_age,
                        std::chrono::duration<Rep,Per> _check_time,
-                       bool _allow_limit_break = false) :
+                       bool _allow_limit_break = false,
+                       double anticipation_timeout = 0.0) :
        super(_client_info_f,
              _idle_age, _erase_age, _check_time,
-             _allow_limit_break)
+             _allow_limit_break, anticipation_timeout)
       {
        can_handle_f = _can_handle_f;
        handle_f = _handle_f;
@@ -1408,14 +1429,16 @@ namespace crimson {
       PushPriorityQueue(typename super::ClientInfoFunc _client_info_f,
                        CanHandleRequestFunc _can_handle_f,
                        HandleRequestFunc _handle_f,
-                       bool _allow_limit_break = false) :
+                       bool _allow_limit_break = false,
+                       double _anticipation_timeout = 0.0) :
        PushPriorityQueue(_client_info_f,
                          _can_handle_f,
                          _handle_f,
                          std::chrono::minutes(10),
                          std::chrono::minutes(15),
                          std::chrono::minutes(6),
-                         _allow_limit_break)
+                         _allow_limit_break,
+                         _anticipation_timeout)
       {
        // empty
       }
index ee4172dc348ac5daebb13c3ec08541472b8b7a1b..94ba2c60ef530f7978548f9840b92274bc751726 100644 (file)
@@ -109,7 +109,6 @@ namespace crimson {
 
       dmc::ServiceTracker<ServerId> st(std::chrono::seconds(2),
                                        std::chrono::seconds(3));
-
       auto rp1 = st.get_req_params(server1);
 
       EXPECT_EQ(1u, rp1.delta) <<
@@ -128,6 +127,7 @@ namespace crimson {
        "rho should be 1 with no intervening reservation responses by" <<
        "other servers";
 
+      // RESPONSE
       st.track_resp(server1, dmc::PhaseType::priority);
 
       auto rp3 = st.get_req_params(server1);
@@ -139,11 +139,12 @@ namespace crimson {
        "rho should be 1 with no intervening reservation responses by" <<
        "other servers";
 
+      // RESPONSE
       st.track_resp(server2, dmc::PhaseType::priority);
 
       auto rp4 = st.get_req_params(server1);
 
-      EXPECT_EQ(2u, rp4.delta) <<
+      EXPECT_EQ(1u, rp4.delta) <<
        "delta should be 2 with one intervening priority response by " <<
        "another server";
       EXPECT_EQ(1u, rp4.rho) <<
@@ -159,19 +160,18 @@ namespace crimson {
        "rho should be 1 with no intervening reservation responses by" <<
        "other servers";
 
+      // RESPONSE
       st.track_resp(server2, dmc::PhaseType::reservation);
 
       auto rp6 = st.get_req_params(server1);
 
-      EXPECT_EQ(2u, rp6.delta) <<
+      EXPECT_EQ(1u, rp6.delta) <<
        "delta should be 2 with one intervening reservation response by " <<
        "another server";
-      EXPECT_EQ(2u, rp6.rho) <<
+      EXPECT_EQ(1u, rp6.rho) <<
        "rho should be 2 with one intervening reservation responses by " <<
        "another server";
 
-      // auto rp6_b = st.get_req_params(server2);
-
       st.track_resp(server2, dmc::PhaseType::reservation);
       st.track_resp(server1, dmc::PhaseType::priority);
       st.track_resp(server2, dmc::PhaseType::priority);
@@ -183,19 +183,19 @@ namespace crimson {
       auto rp7 = st.get_req_params(server1);
 
       EXPECT_EQ(5u, rp7.delta) <<
-       "delta should be 5 with fourintervening responses by " <<
+       "delta should be 5 with four intervening responses by " <<
        "another server";
-      EXPECT_EQ(3u, rp7.rho) <<
-       "rho should be 3 with two intervening reservation responses by " <<
+      EXPECT_EQ(1u, rp7.rho) <<
+       "rho should be 1 with two intervening reservation responses by " <<
        "another server";
 
       auto rp7b = st.get_req_params(server2);
 
-      EXPECT_EQ(4u, rp7b.delta) <<
-       "delta should be 4 with three intervening responses by " <<
+      EXPECT_EQ(9u, rp7b.delta) <<
+       "delta should be 9 with three intervening responses by " <<
        "another server";
-      EXPECT_EQ(2u, rp7b.rho) <<
-       "rho should be 2 with one intervening reservation responses by " <<
+      EXPECT_EQ(4u, rp7b.rho) <<
+       "rho should be 4 with one intervening reservation responses by " <<
        "another server";
 
       auto rp8 = st.get_req_params(server1);
@@ -215,5 +215,85 @@ namespace crimson {
        "rho should be 1 with no intervening reservation responses by " <<
        "another server";
     } // TEST
+
+
+    // NB: the BorrowingTracker has not been fully tested and the
+    // expected values below have not yet been compared with the
+    // theoretically correct values.
+    TEST(dmclock_client, orig_tracker_delta_rho_values) {
+      using ServerId = int;
+
+      ServerId server1 = 101;
+      ServerId server2 = 7;
+
+      dmc::ServiceTracker<ServerId,OrigTracker>
+       st(std::chrono::seconds(2), std::chrono::seconds(3));
+
+      auto rp1 = st.get_req_params(server1);
+
+      EXPECT_EQ(1u, rp1.delta);
+      EXPECT_EQ(1u, rp1.rho);
+
+      auto rp2 = st.get_req_params(server1);
+
+      EXPECT_EQ(1u, rp2.delta);
+      EXPECT_EQ(1u, rp2.rho);
+
+      st.track_resp(server1, dmc::PhaseType::priority);
+
+      auto rp3 = st.get_req_params(server1);
+
+      EXPECT_EQ(1u, rp3.delta);
+      EXPECT_EQ(1u, rp3.rho);
+
+      st.track_resp(server2, dmc::PhaseType::priority);
+
+      auto rp4 = st.get_req_params(server1);
+
+      EXPECT_EQ(2u, rp4.delta);
+      EXPECT_EQ(1u, rp4.rho);
+
+      auto rp5 = st.get_req_params(server1);
+
+      EXPECT_EQ(1u, rp5.delta);
+      EXPECT_EQ(1u, rp5.rho);
+
+      st.track_resp(server2, dmc::PhaseType::reservation);
+
+      auto rp6 = st.get_req_params(server1);
+
+      EXPECT_EQ(2u, rp6.delta);
+      EXPECT_EQ(2u, rp6.rho);
+
+      // auto rp6_b = st.get_req_params(server2);
+
+      st.track_resp(server2, dmc::PhaseType::reservation);
+      st.track_resp(server1, dmc::PhaseType::priority);
+      st.track_resp(server2, dmc::PhaseType::priority);
+      st.track_resp(server2, dmc::PhaseType::reservation);
+      st.track_resp(server1, dmc::PhaseType::reservation);
+      st.track_resp(server1, dmc::PhaseType::priority);
+      st.track_resp(server2, dmc::PhaseType::priority);
+
+      auto rp7 = st.get_req_params(server1);
+
+      EXPECT_EQ(5u, rp7.delta);
+      EXPECT_EQ(3u, rp7.rho);
+
+      auto rp7b = st.get_req_params(server2);
+
+      EXPECT_EQ(4u, rp7b.delta);
+      EXPECT_EQ(2u, rp7b.rho);
+
+      auto rp8 = st.get_req_params(server1);
+
+      EXPECT_EQ(1u, rp8.delta);
+      EXPECT_EQ(1u, rp8.rho);
+
+      auto rp8b = st.get_req_params(server2);
+      EXPECT_EQ(1u, rp8b.delta);
+      EXPECT_EQ(1u, rp8b.rho);
+    } // TEST
+
   } // namespace dmclock
 } // namespace crimson