forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
QuManager.cpp
1 
9 /*
10 Implementation Notes
11 We maintain two heaps defined on the links. The active heap
12 contains links for which packets are currently queued. The
13 vactive heap contains links that are "virtually active", meaning
14 that they recently sent their last packet, but they are not
15 yet allowed to send their next, given the limit on their bit
16 rate and packet rate. If a packet arrives for a virtually active
17 link, it is moved to the active heap with a deadline inherited
18 from the vactive heap.
19 
20 It's important that links be moved off the vactive heap when
21 they become eligible to send new packets. This is done in the
22 nextReady routine, which is expected to be called frequently
23 (e.g. once on each iteration of the router's main loop).
24 
25 In addition to the active and vactive heaps, there is a HeapSet
26 data structure that contains a heap for each link. These heaps
27 contain queues and the key of a queue in its heap, is the
28 virtual finish time of the queue in a Self-Clocked Fair Queueing
29 packet scheduler.
30 */
31 
32 #include "QuManager.h"
33 
34 namespace forest {
35 
36 
37 // Constructor for QuManager, allocates space and initializes everything.
38 QuManager::QuManager(int nL1, int nP1, int nQ1, int maxppl1,
39  PacketStore *ps1, StatsModule *sm1)
40  : nL(nL1), nP(nP1), nQ(nQ1),
41  maxppl(maxppl1), ps(ps1), sm(sm1) {
42  queues = new ListSet(nP,nQ);
43  active = new Dheap<uint64_t>(nL);
44  vactive = new Dheap<uint64_t>(nL);
45  quInfo = new QuInfo[nQ+1];
46  lnkInfo = new LinkInfo[nL+1];
47  hset = new DheapSet<uint64_t>(nQ,nL);
48 
51  for (int lnk = 1; lnk <= nL; lnk++) {
52  lnkInfo[lnk].vt = 0; setLinkRates(lnk, rs);
53  }
54 
55  // build free list of queues using lnk field
56  for (int qid = 1; qid < nQ; qid++) {
57  quInfo[qid].lnk = qid+1;
58  quInfo[qid].pktLim = -1; // used to identify unassigned queues
59  quInfo[qid].vft = 0;
60  }
61  quInfo[nQ].lnk = 0; free = 1;
62  qCnt = 0;
63 }
64 
65 QuManager::~QuManager() {
66  delete queues; delete active; delete vactive;
67  delete [] quInfo; delete [] lnkInfo; delete hset;
68 }
69 
74 int QuManager::allocQ(int lnk) {
75  unique_lock lck(mtx);
76  if (free == 0) return 0;
77  int qid = free; free = quInfo[qid].lnk;
78  quInfo[qid].lnk = lnk;
79  quInfo[qid].pktLim = 0; // non-negative value for assigned queues
80  qCnt++;
81  return qid;
82 }
83 
90 void QuManager::freeQ(int qid) {
91  unique_lock lck(mtx);
92  if (qid == 0) return;
93  if (queues->empty(qid)) {
94  quInfo[qid].lnk = free; free = qid; qCnt--;
95  }
96  quInfo[qid].pktLim = -1; // negative value for free queues
97 }
98 
107 bool QuManager::enq(int px, int qid, uint64_t now) {
108  unique_lock lck(mtx);
109  int pleng = Forest::truPktLeng((ps->getPacket(px)).length);
110  QuInfo& q = quInfo[qid]; int lnk = q.lnk;
111 
112  // don't queue it if too many packets for link
113  // or if queue is past its limits
114  if (sm->getLinkQlen(lnk) >= maxppl ||
115  sm->getQlen(qid) >= q.pktLim ||
116  sm->getQbytes(qid) + pleng > q.byteLim) {
117  return false;
118  }
119 
120  if (queues->empty(qid)) {
121  // make link active if need be
122  if (!active->member(lnk)) {
123  uint64_t d;
124  if (vactive->member(lnk)) {
125  d = vactive->key(lnk);
126  if (now >= d) d = now;
127  vactive->remove(lnk);
128  } else {
129  d = now;
130  lnkInfo[lnk].avgPktTime = lnkInfo[lnk].minDelta;
131  }
132  active->insert(lnk,d);
133  }
134  // set virtual finish time of queue
135  uint64_t d = q.nsPerByte; d *= pleng;
136  if (q.minDelta > d) d = q.minDelta;
137  q.vft = max(q.vft, lnkInfo[lnk].vt) + d;
138 
139  // add queue to scheduling heap for link
140  if (!hset->insert(qid,q.vft,lnk)) {
141  cerr << "enq attempt to insert in hset failed qid="
142  << qid << " lnk=" << lnk << " hset="
143  << hset->toString(lnk);
144  }
145  }
146 
147  // add packet to queue
148  queues->addLast(px,qid);
149  sm->incQlen(qid,lnk,pleng);
150  return true;
151 }
152 
160 int QuManager::deq(int& lnk, uint64_t now) {
161  unique_lock lck(mtx);
162  // first process virtually active links that should now be idle
163  //
164  int vl = vactive->findmin(); uint64_t d = vactive->key(vl);
165  while (vl != 0 && now >= d) {
166  vactive->remove(vl);
167  vl = vactive->findmin(); d = vactive->key(vl);
168  }
169  // determine next active link that is ready to send
170  if (active->empty()) return 0;
171  lnk = active->findmin(); d = active->key(lnk);
172  if (now < d) return 0;
173 
174  // dequeue packet and update statistics
175  int qid = hset->findMin(lnk);
176  pktx px = queues->removeFirst(qid);
177  int pleng = Forest::truPktLeng(ps->getPacket(px).length);
178  sm->decQlen(qid,lnk,pleng);
179 
180  // and update scheduling heap and virtual time of lnk
181  QuInfo& q = quInfo[qid];
182  lnkInfo[lnk].vt = q.vft;
183  if (queues->empty(qid)) {
184  hset->deleteMin(lnk);
185  if (q.pktLim < 0) {
186  // move queue to the free list
187  q.lnk = free; free = qid; qCnt--;
188  }
189  } else {
190  int npx = queues->first(qid);
191  Packet& np = ps->getPacket(npx);
192  int npleng = Forest::truPktLeng(np.length);
193  uint64_t d = q.nsPerByte; d *= npleng;
194  if (q.minDelta > d) d = q.minDelta;
195  q.vft += d;
196  hset->changeKeyMin(q.vft, lnk);
197  }
198 
199  // update the time when lnk can send its next packet
200  uint64_t t = lnkInfo[lnk].nsPerByte; t *= pleng;
201  lnkInfo[lnk].avgPktTime = (t/16) + (15*(lnkInfo[lnk].avgPktTime/16));
202  if (lnkInfo[lnk].avgPktTime < lnkInfo[lnk].minDelta &&
203  t < lnkInfo[lnk].minDelta)
204  t = lnkInfo[lnk].minDelta;
205  t += active->key(lnk);
206 
207  if (hset->empty(lnk)) {
208  active->remove(lnk);
209  vactive->insert(lnk,t);
210  } else {
211  active->changekey(lnk,t);
212  }
213 
214  return px;
215 }
216 
217 } // ends namespace
218