Wednesday, December 17, 2008

PiecePicking and runtime method overriding

Deciding which chunk of data to download next is a pretty complex task in the bittorrent world. You have to take into account a number of factors, such as:
1) You may want to prefer to download rare pieces first, maybe not.
2) You may want to pick a piece randomly, or maybe you want to download from the start of the file and get pieces in order
3) The user may set a higher priority on a certain file, so you should prefer its pieces.
4) The user may want to ignore certain files and never select their pieces.

Then imagine trying to NUnit test all the combinations and you'll find that it becomes very difficult to ensure the implementation is correct and impossible to extend with new behavior because the interactions become too complex.

The basic premise I had when redesigning this area of code was this: When I want to change the picking behaviour, I want to override one single method and then just slot the picker into the pipeline. So here's a reduced version of the PiecePicker class (3 methods instead of 10) and an example of how it's implemented.

public abstract class PiecePicker
{
protected PiecePicker(PiecePicker picker)
{
this.picker = picker;
}

void CheckOverriden()
{
if (picker == null)
throw new InvalidOperationException("This method must be overridden");
}

public virtual void Initialise(BitField bitfield, TorrentFile[] files, IEnumerable<Piece> requests)
{
CheckOverriden();
picker.Initialise(bitfield, files, requests);
}

public virtual bool IsInteresting(BitField bitfield)
{
CheckOverriden();
return picker.IsInteresting(bitfield);
}

public virtual MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int startIndex, int endIndex, int count)
{
CheckOverriden();
return picker.PickPiece(id, peerBitfield, otherPeers, startIndex, endIndex, count);
}
}


public class RandomisedPicker : PiecePicker
{
Random random
= new Random();

public RandomisedPicker(PiecePicker picker)
:
base(picker)
{

}

public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int startIndex, int endIndex, int count)
{
MessageBundle message;
int midpoint = random.Next(startIndex, endIndex);
if ((message = base.PickPiece(id, peerBitfield, otherPeers, midpoint, endIndex, count)) != null)
return message;
else
return base.PickPiece(id, peerBitfield, otherPeers, startIndex, midPoint, count);
}
}



Here's a usage example:
// StandardPicker provides an implementation for every method in PiecePicker
PiecePicker p = new RandomisedPicker(new StandardPicker);


So what happens is this:
1) p.PickPiece is called which results in RandomisedPicker.PickPiece being called
2) This splits the range between startIndex/endIndex into two and then makes two calls to base.PickPiece.
3) base.PickPiece will call standardPicker.PickPiece (because the 'picker' is non-null)
4) standardPicker.PickPiece will see if there are any pieces to request, and choose the first available one

Suppose I wanted to be able to ignore all the pieces which I already own, well, that's easy, I just use an IgnoringPicker (not a great name I'll admit):

public class IgnoringPicker : PiecePicker
{
BitField bitfield;
BitField temp;

public IgnoringPicker(BitField bitfield, PiecePicker picker)
:
base(picker)
{
this.bitfield = bitfield;
this.temp = new BitField(bitfield.Length);
}

public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List<PeerId> otherPeers, int startIndex, int endIndex, int count)
{
// In binary operations: temp = peerBitfield & (~bitfield);
temp.SetAll(false).Or(peerBitfield).NAnd(bitfield);
return base.PickPiece(id, temp, otherPeers, startIndex, endIndex, count);
}

public override bool IsInteresting(BitField bitfield)
{
temp.SetAll(
false).Or(bitfield).NAnd(this.bitfield);
return base.IsInteresting(temp);
}
}


Now i just change my usage to:
Picker picker = new StandardPicker ();
picker
= new RandomisedPicker (picker);
picker
= new IgnoringPicker (myBitfield, picker);


The biggest benefit is that each individual picking logic unit can very easily tested. They can then be combined in any order you want to change the picking behaviour. Random->Rarest->Standard would be different to Rarest->Random->Standard. The former will give you the rarest piece in a random set, the latter will give you a random piece from the rarest set.

The implementation of a logic unit is also trivial - you only have to override the behaviour you want to change rather than implementing a massive interface where for 90% of the methods you end up calling basePicker.Method anyway. So I'm quite happy with this change. This code already passes all the NUnit tests from the old picker as well as all the new tests I've written, so it should be going live in the near future. There's still some more work to be done before it's complete.

9 comments:

Scott said...

I'll be honest, this is a really cool API design. Did you come up with this all by yourself, or did you find a similar pattern somewhere?

Anonymous said...

I struggled for quite a while to understand this (i hadn't found this blog, and your code isn't exactly well-commented ;), but once I did, I fell in love with it.

Seriously, this is a great way to do this. Nice job!

Anonymous said...

福井出会いカフェ愛知出会いカフェ岐阜出会いカフェ静岡出会いカフェ三重出会いカフェ兵庫出会いカフェ大阪出会いカフェ和歌山出会いカフェ滋賀出会いカフェ京都出会いカフェ奈良出会いカフェ山口出会いカフェ鳥取出会いカフェ島根出会いカフェ岡山出会いカフェ広島出会いカフェ徳島出会いカフェ香川出会いカフェ愛媛出会いカフェ高知出会いカフェ

Anonymous said...

免費視訊,煙火,煙火工廠,視訊,正妹視訊,真愛密碼,真愛密碼,煙火秀,煙火圖片,衣蝶,衣蝶,AV女優,AV女優,
煙火批發,小泉彩,小泉彩,情趣用品,鞭炮,live119論壇,蜂炮,視訊

Oci Beken said...

How about if i want it from the beginning?
if the first piece is not there than Download the first piece first.

梁爵 said...

2019.12.11Googel搜尋找到可以信賴的酒店經紀人後,接下來就是約時間當面聊,把妳的需求告訴酒店經紀人,也讓酒店經紀人看看妳的條件適合哪種店家。同時也會依照小姐的不同條件列出10來家酒店名單最後由您自己選擇喜歡理想的酒店工作環境。
酒店上班的種類很多,光大台北地區分為東區、中山區兩大區塊就有分類便服店、禮服店、制服店、鋼琴酒吧、日式酒店、飯局、傳播。洋洋灑灑加總就30幾家酒店每種類型酒店所需要小姐的條件也不同,於是酒店小姐這份工作是競爭的。八大行業酒店小姐成績不理想也是會被裁員的(如:酒店小姐上班收入比白天工作薪資還少…就是酒店業者裁員的對象)。
1: 酒店打工小姐們如何判斷自己適合在什麼的店呢?誠懇面對自己外型條件吧(外表是可以調整的)這行是以外型取勝!(當然沒有人願意犧牲啊),任何一份工作都有它辛苦的面何況高收入的八大行業。
2: 酒店兼差一週可以上幾天班? 能配合哪個時間打卡上班? 是否有門禁問題?
3: 酒店工作和白天工作一樣!目標是一樣的就是【賺錢】都是要花固定的時間來上班(如:服裝、髮妝、談吐、氣質)把最好的展現出來。上班天數多寡,當然取決於妳的收入。
4: 選擇酒店經紀很重要,小姐放在對的酒店一天酒店兼職可以賺個$5000~$8000不是問題。如果酒店小姐收入不如預期,而店裡生意也不差,妳就要思考是否繼續這份競爭力的環境!應該考慮換店或換跑道,(別等店家開口要妳離職)。
2020不怕找不到酒店經紀 大數據Google搜尋:梁曉尊/梁小尊
不擔心拿低薪 高水平 高標準 公開 透明 亞洲地區Google認證

梁爵 said...

2020.05.14酒店舞廳可不可復業?酒店小姐的基本介紹跟工作內容台北市長柯文哲今天在議會表示,他還是等陳時中,「他(陳時中)不宣布,我(柯文哲)就來宣布」。柯又提到,市府正在評估5月25日第二波要解封的部分。對於我在酒店上班的日子有媒體解讀,北市府25日將解封酒店小姐一定有S?酒店舞廳?梁小尊表示 八大行業是哪八種行業呢?,柯文哲今天上午至議會專案報告職場須知 【酒店PT 】答詢時,從未提及5月25日將解封酒店、舞廳等地點。梁曉尊強調,5月25日起將啟動酒店打工第二波解封場館名單,至於八大行業解封日期仍在討論中,對於如何落實防疫新生活運動四原則,本府已正式行文衛福部,盼中央能給予執行方式與裁罰規定。

梁爵 said...

2020.10.31網紅「【酒店小姐】【酒店公關】橫綱凱咪」(Aqq cami)日前在臉書爆料酒店小姐的基本介紹跟工作內容,指網美圈有7成都在酒店兼差可以現領賣淫,除了引起外界討論,也讓不少知名網紅躺著中槍。對此,資深媒體人羅友志近日受訪時透露,類似酒店小姐酒店上班的價目表其實都是故意流出,藉此炒作身價,而大老闆們若有意尋芳,便會和媽媽桑聯絡,再透過一套「買春SOP」進行交易。不敢來酒店上班-酒店打工的原因報導,羅友志表示,以他過去跑新聞的經歷來看,類似的女藝人、飯局妹或小模的價目表會曝光,通常都是有人刻意炒作,因為價碼一出來,坊間就會開始影射、穿鑿附會,只要有新聞話題,一些大老闆及有錢人自然會產生興趣,女孩們的身價也會跟著提高,算是一種相當有效的行銷手法。羅友志提到,現在的網紅大致分為2種,如果是高人氣的百大網紅,必須得顧及面子和名聲,不可能公開讓人知道自己有在做,多數都會姑隱其名,然而雞頭又必須讓客人知道小姐的來頭不小,所以常會在底下加註一些暗示性的資訊,例如上過的節目、個人特徵等,如果服務口碑良好,身價也會翻倍。至於賣淫方式,羅友志指出,有錢人和網紅性交易,一方不想說「嫖」,另一邊也不想承認自己「被嫖」,於是便衍生出了一套獨特的SOP,例如媽媽桑成立公關公司,再安排旗下小姐和大老闆約會,當天不會有任何金錢交易,之後以合作的形式付錢給公關公司,經紀抽頭後再分給小姐,如此一來三方都得利。最後,羅友志也奉勸現在年輕女孩,賣淫這種事只要做過一次,未來就難以脫身,不要認為一時缺錢花用,偶爾為之無傷大雅,再說歲月是無情的,現在好賺是因為年輕,等到年紀漸長、失去行情後,就只能淪落到酒店甚至站壁,更別提「每個人都會跟大家講,我睡過她,那印章永遠都會蓋在身上。」

梁爵 said...

八大行業陸續開放解禁,許多酒店、酒吧以及娛樂場所紛紛重新開始營業,但酒店卻面臨「酒店打工缺妹」窘境,幾乎每家酒店都只有4至6成的酒店上班公關回流,有的跑去接飯局,另外也有公關接觸白天班後轉行,所以各家酒店幾乎「漲聲響起」。
據了解,八大停業6個月左右,許多酒店上班酒店公關紛紛沒有工作,有的出國接局,但因出國遭境外海關管制,所以也有人轉往私人招待所轉做飯局妹,另外酒店工作也有不少酒店妹選擇白天工作,在八大陸續解禁開放,也引發「酒店工作缺妹潮」。
有老司機表示,北市酒店大約分成4種型態,分別為便服店、禮服店以及日式酒店制服店,依照店面的大小、設置的包廂數,會由經紀公司安排酒店公關前往上班,但是現在因疫情影響,所以許多酒店公關轉職後也不願意回到酒店上班。
許多酒店因為「缺妹潮」,幾乎酒店公關都不回來上班,從復業至今,酒店公關上班人數僅以前的5、6成,所以也紛紛提高給經紀公司、酒店公關的時數錢,平均增加了10%的價格,所以自然也就反應在酒店消費者身上。
據悉酒店消費的消費者,北市酒店幾乎全面喊漲,甚至連酒價也跟著漲,也些店家還會收取人頭費,有消費者透露,目前除了酒店缺妹之外,另外酒店公關的費用也增加了約百分之10,所以許多酒店妹紛紛轉往當飯局妹或傳播妹、日式酒店
老司機透露,原本飯局的價格4個小時要價6千至1萬2千元,第5個小時開始,每個小時收取1千元費用,但也因酒店復業,所以造成酒店兼差的酒店公關回流,甚至開始喊到第5個小時開始,每個小時要價1千5百元。

Hit Counter