// i.towards(bin);
//printf("at %i ",i.half);
//dump("get made");
- return *i; // deep cell is never 0xffff or 0x0000
+ return *i; // deep cell is never 0xffff or 0x0000; FIXME: API caveat
}
}
-bool bins::is_empty (bin64_t range) {
+bool bins::is_solid (bin64_t range, fill_t val) {
if (range==bin64_t::ALL)
- return !deep(0) && !halves[0];
+ return !deep(0) && (is_mixed(val) || halves[0]==val);
iterator i(this,range,false);
while ( i.pos!=range && (i.deep() || !i.solid()) )
i.towards(range);
- return !i.deep() && *i==EMPTY;
+ return i.solid() && (is_mixed(val) || *i==val);
}
class bins {
public:
- typedef enum { FILLED=0xffff, EMPTY=0x0000 } fill_t;
+ typedef enum { FILLED=0xffff, EMPTY=0x0000, MIXED=0x5555 } fill_t;
static const int NOJOIN;
bins();
uint64_t mass ();
- bool is_empty (bin64_t range=bin64_t::ALL) ;
+ bool is_solid (bin64_t range=bin64_t::ALL, fill_t val=MIXED) ;
+ bool is_empty (bin64_t range=bin64_t::ALL) { return is_solid(range,EMPTY); }
+ bool is_filled (bin64_t range=bin64_t::ALL) { return is_solid(range,FILLED); }
void clear ();
static bool is_mixed (uint16_t val) { return val!=EMPTY && val!=FILLED; }
+ static bool is_solid (uint16_t val) { return val==EMPTY || val==FILLED; }
void twist (uint64_t mask);
~iterator();
bool deep () { return host->deep(half); }
bool solid () {
- return !deep() && (host->halves[half]==bins::FILLED ||
- host->halves[half]==bins::EMPTY);
+ return !deep() && bins::is_solid(host->halves[half]);
}
void sibling () { half^=1; pos=pos.sibling(); }
bool end () { return half==1; }
#!/bin/bash
-for tst in `ls tests/*test`; do
+for tst in `ls tests/*test | grep -v ledbat`; do
if echo $tst; $tst > $tst.log; then
echo $tst OK
else
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "bin64.h"
+
+int main (int argn, char** args) {
+ int lr;
+ unsigned long long of;
+ sscanf(args[1],"%i,%lli",&lr,&of);
+ bin64_t target(lr,of);
+ char line[1024];
+ while (gets(line)) {
+ char* br = strchr(line,'(');
+ if (br && 2==sscanf(br,"(%i,%lli)",&lr,&of)) {
+ bin64_t found(lr,of);
+ if ( found.within(target) || target.within(found))
+ printf("%s\n",line);
+ }
+ }
+ return 0;
+}
}
/** Get a request for one packet from the queue of peer's requests. */
bin64_t DequeueHint();
- void ClearStaleDataOut ();
+ void CleanDataOut (bin64_t acks_pos=bin64_t::NONE);
void CleanStaleHintOut();
void CleanHintOut(bin64_t pos);
- void CleanFulfilledDataOut(bin64_t pos);
void Schedule(tint send_time);
static PeerSelector* peer_selector;
}
-void Channel::ClearStaleDataOut() {
- int oldsize = data_out_.size();
- tint timeout = NOW - max( rtt_avg_-dev_avg_*4, 500*TINT_MSEC );
- while ( data_out_.size() && data_out_.front().time < timeout &&
- ack_in_.get(data_out_.front().bin)==bins::EMPTY ) {
- dprintf("%s #%i Tdata %s\n",tintstr(),id,data_out_.front().bin.str());
- data_out_.pop_front();
- }
- if (data_out_.size()!=oldsize) {
- cc_->OnAckRcvd(bin64_t::NONE);
- data_out_cap_ = bin64_t::ALL;
- }
- while (data_out_.size() && (data_out_.front()==tintbin() || ack_in_.get(data_out_.front().bin)==bins::FILLED))
- data_out_.pop_front();
-}
-
-
void Channel::Send () {
Datagram dgram(socket_,peer());
dgram.Push32(peer_channel_id_);
if (!file().is_complete())
AddHint(dgram);
AddPex(dgram);
- ClearStaleDataOut();
+ CleanDataOut();
data = AddData(dgram);
} else {
AddHandshake(dgram);
}
-void Channel::CleanFulfilledDataOut (bin64_t ackd_pos) {
- for (int i=0; i<8 && i<data_out_.size(); i++)
- if (data_out_[i]!=tintbin() && data_out_[i].bin.within(ackd_pos)) {
- tint rtt = NOW-data_out_[i].time;
- rtt_avg_ = (rtt_avg_*7 + rtt) >> 3;
- dev_avg_ = ( dev_avg_*3 + abs(rtt-rtt_avg_) ) >> 2;
- dprintf("%s #%i rtt %lli dev %lli\n",
- tintstr(),id,rtt_avg_,dev_avg_);
- cc_->OnAckRcvd(data_out_[i].bin);
- data_out_[i]=tintbin();
+void Channel::CleanDataOut (bin64_t ackd_pos) {
+
+ int max_ack_off = 0;
+
+ if (ackd_pos!=bin64_t::NONE) {
+ for (int i=0; i<8 && i<data_out_.size(); i++) {
+ if (data_out_[i]!=tintbin() && data_out_[i].bin.within(ackd_pos)) {
+ tint rtt = NOW-data_out_[i].time;
+ rtt_avg_ = (rtt_avg_*7 + rtt) >> 3;
+ dev_avg_ = ( dev_avg_*3 + abs(rtt-rtt_avg_) ) >> 2;
+ dprintf("%s #%i rtt %lli dev %lli\n",tintstr(),id,rtt_avg_,dev_avg_);
+ bin64_t pos = data_out_[i].bin;
+ cc_->OnAckRcvd(pos);
+ data_out_[i]=tintbin();
+ max_ack_off = i;
+ if (ackd_pos==pos)
+ break;
+ }
+ }
+ while (!data_out_.empty() && data_out_.front().bin==bin64_t::NONE) {
+ data_out_.pop_front();
+ max_ack_off--;
+ }
+ static const int MAX_REORDERING = 2; // the triple-ACK principle
+ if (max_ack_off>MAX_REORDERING) {
+ while (max_ack_off && ack_in_.is_filled(data_out_.front().bin)) {
+ data_out_.pop_front();
+ max_ack_off--;
+ }
+ while (max_ack_off>MAX_REORDERING) {
+ cc_->OnAckRcvd(bin64_t::NONE);
+ data_out_.pop_front();
+ max_ack_off--;
+ data_out_cap_ = bin64_t::ALL;
+ dprintf("%s #%i Rdata %s\n",tintstr(),id,data_out_.front().bin.str());
+ }
+ }
+ }
+ tint timeout = NOW - rtt_avg_ - 4*std::max(dev_avg_,TINT_MSEC*50);
+ while (!data_out_.empty() && data_out_.front().time<timeout) {
+ if (ack_in_.is_empty(data_out_.front().bin)) {
+ cc_->OnAckRcvd(bin64_t::NONE);
+ data_out_cap_ = bin64_t::ALL;
+ dprintf("%s #%i Tdata %s\n",tintstr(),id,data_out_.front().bin.str());
}
- while ( data_out_.size() && ( data_out_.front()==tintbin() ||
- ack_in_.get(data_out_.front().bin)==bins::FILLED ) )
data_out_.pop_front();
+ }
+
}
}
dprintf("%s #%i -ack %s\n",tintstr(),id,ackd_pos.str());
ack_in_.set(ackd_pos);
- CleanFulfilledDataOut(ackd_pos);
+ CleanDataOut(ackd_pos);
}
EXPECT_EQ(11,b.seq_length());
}
+TEST(BinsTest,EmptyFilled) {
+ // 1112 3312 2111 ....
+ bins b;
+
+ EXPECT_TRUE(b.is_empty(bin64_t::ALL));
+
+ b.set(bin64_t(1,0));
+ b.set(bin64_t(0,2));
+ b.set(bin64_t(0,6));
+ b.set(bin64_t(1,5));
+ b.set(bin64_t(0,9));
+
+ EXPECT_FALSE(b.is_empty(bin64_t::ALL));
+
+ EXPECT_TRUE(b.is_empty(bin64_t(2,3)));
+ EXPECT_FALSE(b.is_filled(bin64_t(2,3)));
+ EXPECT_TRUE(b.is_solid(bin64_t(2,3),bins::MIXED));
+ EXPECT_TRUE(b.is_filled(bin64_t(1,0)));
+ EXPECT_TRUE(b.is_filled(bin64_t(1,5)));
+ EXPECT_FALSE(b.is_filled(bin64_t(1,3)));
+
+ b.set(bin64_t(0,3));
+ b.set(bin64_t(0,7));
+ b.set(bin64_t(0,8));
+
+ EXPECT_TRUE(b.is_filled(bin64_t(2,0)));
+ EXPECT_TRUE(b.is_filled(bin64_t(2,2)));
+ EXPECT_FALSE(b.is_filled(bin64_t(2,1)));
+
+ b.set(bin64_t(1,2));
+ EXPECT_TRUE(b.is_filled(bin64_t(2,1)));
+}
+
TEST(BinheapTest,Eat) {
binheap b;