From 74ff353924e9baa8f09e892481091433c42d9f06 Mon Sep 17 00:00:00 2001 From: Jono Wenger <jono@elixxir.io> Date: Wed, 29 Dec 2021 10:29:04 -0800 Subject: [PATCH] Make sentRoundTracker that tracks rounds that file parts were recently sent on --- fileTransfer/sentRoundTracker.go | 101 ++++++++++++++ fileTransfer/sentRoundTracker_test.go | 184 ++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 fileTransfer/sentRoundTracker.go create mode 100644 fileTransfer/sentRoundTracker_test.go diff --git a/fileTransfer/sentRoundTracker.go b/fileTransfer/sentRoundTracker.go new file mode 100644 index 000000000..05ce4b1c3 --- /dev/null +++ b/fileTransfer/sentRoundTracker.go @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package fileTransfer + +import ( + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/netTime" + "sync" + "time" +) + +// sentRoundTracker keeps track of rounds that file parts were sent on and when +// those rounds occurred. Rounds past the given age can be deleted manually. +type sentRoundTracker struct { + rounds map[id.Round]time.Time + age time.Duration + mux sync.RWMutex +} + +// newSentRoundTracker returns an empty sentRoundTracker. +func newSentRoundTracker(interval time.Duration) *sentRoundTracker { + return &sentRoundTracker{ + rounds: make(map[id.Round]time.Time), + age: interval, + } +} + +// removeOldRounds removes any rounds that are older than the max round age. +func (srt *sentRoundTracker) removeOldRounds() { + srt.mux.Lock() + defer srt.mux.Unlock() + deleteBefore := netTime.Now().Add(-srt.age) + + for rid, timeStamp := range srt.rounds { + if timeStamp.Before(deleteBefore) { + delete(srt.rounds, rid) + } + } +} + +// Has indicates if the round ID is in the tracker. +func (srt *sentRoundTracker) Has(rid id.Round) bool { + srt.mux.RLock() + defer srt.mux.RUnlock() + + _, exists := srt.rounds[rid] + return exists +} + +// Insert adds the round to the tracker with the current time. +func (srt *sentRoundTracker) Insert(rid id.Round) { + timeNow := netTime.Now() + srt.mux.Lock() + defer srt.mux.Unlock() + + jww.DEBUG.Printf("[FT]\tInsert round %d into tracker at time %s\n", rid, timeNow.Format("03:04:05.9999999 PM")) + + srt.rounds[rid] = timeNow +} + +// Remove deletes a round ID from the tracker. +func (srt *sentRoundTracker) Remove(rid id.Round) { + srt.mux.Lock() + defer srt.mux.Unlock() + delete(srt.rounds, rid) +} + +// Len returns the number of round IDs in the tracker. +func (srt *sentRoundTracker) Len() int { + srt.mux.RLock() + defer srt.mux.RUnlock() + + return len(srt.rounds) +} + +// GetRoundIDs returns a list of all round IDs in the tracker. +func (srt *sentRoundTracker) GetRoundIDs() []id.Round { + srt.mux.RLock() + defer srt.mux.RUnlock() + + roundIDs := make([]id.Round, 0, len(srt.rounds)) + + for rid := range srt.rounds { + roundIDs = append(roundIDs, rid) + } + + return roundIDs +} diff --git a/fileTransfer/sentRoundTracker_test.go b/fileTransfer/sentRoundTracker_test.go new file mode 100644 index 000000000..451ec1eff --- /dev/null +++ b/fileTransfer/sentRoundTracker_test.go @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package fileTransfer + +import ( + "gitlab.com/xx_network/primitives/id" + "reflect" + "testing" + "time" +) + +// Tests that newSentRoundTracker returns the expected new sentRoundTracker. +func Test_newSentRoundTracker(t *testing.T) { + interval := 10 * time.Millisecond + expected := &sentRoundTracker{ + rounds: make(map[id.Round]time.Time), + age: interval, + } + + srt := newSentRoundTracker(interval) + + if !reflect.DeepEqual(expected, srt) { + t.Errorf("New sentRoundTracker does not match expected."+ + "\nexpected: %+v\nreceived: %+v", expected, srt) + } +} + +// Tests that sentRoundTracker.removeOldRounds removes only old rounds and not +// newer rounds. +func Test_sentRoundTracker_removeOldRounds(t *testing.T) { + srt := newSentRoundTracker(50 * time.Millisecond) + + // Add odd round to tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 != 0 { + srt.Insert(rid) + } + } + + time.Sleep(50 * time.Millisecond) + + // Add even round to tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 == 0 { + srt.Insert(rid) + } + } + + // Remove all old rounds (should be all odd rounds) + srt.removeOldRounds() + + // Check that only even rounds exist + for rid := id.Round(0); rid < 100; rid++ { + if srt.Has(rid) { + if rid%2 != 0 { + t.Errorf("Round %d exists.", rid) + } + } else if rid%2 == 0 { + t.Errorf("Round %d does not exist.", rid) + } + } +} + +// Tests that sentRoundTracker.Has returns true for all the even rounds and +// false for all odd rounds. +func Test_sentRoundTracker_Has(t *testing.T) { + srt := newSentRoundTracker(0) + + // Insert even rounds into the tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 == 0 { + srt.Insert(rid) + } + } + + // Check that only even rounds exist + for rid := id.Round(0); rid < 100; rid++ { + if srt.Has(rid) { + if rid%2 != 0 { + t.Errorf("Round %d exists.", rid) + } + } else if rid%2 == 0 { + t.Errorf("Round %d does not exist.", rid) + } + } +} + +// Tests that sentRoundTracker.Insert adds all the expected rounds. +func Test_sentRoundTracker_Insert(t *testing.T) { + srt := newSentRoundTracker(0) + + // Insert even rounds into the tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 == 0 { + srt.Insert(rid) + } + } + + // Check that only even rounds were added + for rid := id.Round(0); rid < 100; rid++ { + _, exists := srt.rounds[rid] + if exists { + if rid%2 != 0 { + t.Errorf("Round %d exists.", rid) + } + } else if rid%2 == 0 { + t.Errorf("Round %d does not exist.", rid) + } + } +} + +// Tests that sentRoundTracker.Remove removes all even rounds. +func Test_sentRoundTracker_Remove(t *testing.T) { + srt := newSentRoundTracker(0) + + // Add all round to tracker + for rid := id.Round(0); rid < 100; rid++ { + srt.Insert(rid) + } + + // Remove even rounds from the tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 == 0 { + srt.Remove(rid) + } + } + + // Check that only even rounds were removed + for rid := id.Round(0); rid < 100; rid++ { + _, exists := srt.rounds[rid] + if exists { + if rid%2 == 0 { + t.Errorf("Round %d does not exist.", rid) + } + } else if rid%2 != 0 { + t.Errorf("Round %d exists.", rid) + } + } +} + +// Tests that sentRoundTracker.Len returns the expected length when the tracker +// is empty, filled, and then modified. +func Test_sentRoundTracker_Len(t *testing.T) { + srt := newSentRoundTracker(0) + + if srt.Len() != 0 { + t.Errorf("Length of tracker incorrect.\nexpected: %d\nreceived: %d", + 0, srt.Len()) + } + + // Add all round to tracker + for rid := id.Round(0); rid < 100; rid++ { + srt.Insert(rid) + } + + if srt.Len() != 100 { + t.Errorf("Length of tracker incorrect.\nexpected: %d\nreceived: %d", + 100, srt.Len()) + } + + // Remove even rounds from the tracker + for rid := id.Round(0); rid < 100; rid++ { + if rid%2 == 0 { + srt.Remove(rid) + } + } + + if srt.Len() != 50 { + t.Errorf("Length of tracker incorrect.\nexpected: %d\nreceived: %d", + 50, srt.Len()) + } +} -- GitLab