diff --git a/model/filequeue.go b/model/filequeue.go index 08588b15..ff7620f0 100644 --- a/model/filequeue.go +++ b/model/filequeue.go @@ -192,6 +192,15 @@ func (q *FileQueue) deleteAt(i int) { q.files = q.files[:i+copy(q.files[i:], q.files[i+1:])] } +func (q *FileQueue) deleteFile(n string) { + for i, file := range q.files { + if n == file.name { + q.deleteAt(i) + return + } + } +} + func (q *FileQueue) SetAvailable(file, node string) { q.lock.Lock() defer q.lock.Unlock() @@ -209,3 +218,19 @@ func (q *FileQueue) AddAvailable(file, node string) { } q.availability[file] = append(q.availability[file], node) } + +func (q *FileQueue) RemoveAvailable(toRemove string) { + q.lock.Lock() + defer q.lock.Unlock() + for file, nodes := range q.availability { + for i, node := range nodes { + if node == toRemove { + q.availability[file] = nodes[:i+copy(nodes[i:], nodes[i+1:])] + if len(q.availability[file]) == 0 { + q.deleteFile(file) + } + } + break + } + } +} diff --git a/model/filequeue_test.go b/model/filequeue_test.go index fcb44870..e43351a5 100644 --- a/model/filequeue_test.go +++ b/model/filequeue_test.go @@ -2,30 +2,21 @@ package model import ( "reflect" - "strings" "sync" "sync/atomic" "testing" ) -type fakeResolver struct{} - -func (fakeResolver) WhoHas(n string) []string { - if strings.HasPrefix(n, "a-") { - return []string{"a", "nodeID"} - } else if strings.HasPrefix(n, "b-") { - return []string{"b", "nodeID"} - } - return []string{"a", "b", "nodeID"} -} - func TestFileQueueAdd(t *testing.T) { q := FileQueue{} q.Add("foo", nil, nil) } func TestFileQueueAddSorting(t *testing.T) { - q := FileQueue{resolver: fakeResolver{}} + q := FileQueue{} + q.SetAvailable("zzz", "nodeID") + q.SetAvailable("aaa", "nodeID") + q.Add("zzz", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil) q.Add("aaa", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil) b, _ := q.Get("nodeID") @@ -33,7 +24,10 @@ func TestFileQueueAddSorting(t *testing.T) { t.Errorf("Incorrectly sorted get: %+v", b) } - q = FileQueue{resolver: fakeResolver{}} + q = FileQueue{} + q.SetAvailable("zzz", "nodeID") + q.SetAvailable("aaa", "nodeID") + q.Add("zzz", []Block{{Offset: 0, Size: 128}, {Offset: 128, Size: 128}}, nil) b, _ = q.Get("nodeID") // Start on zzzz if b.name != "zzz" { @@ -58,7 +52,10 @@ func TestFileQueueLen(t *testing.T) { } func TestFileQueueGet(t *testing.T) { - q := FileQueue{resolver: fakeResolver{}} + q := FileQueue{} + q.SetAvailable("foo", "nodeID") + q.SetAvailable("bar", "nodeID") + q.Add("foo", []Block{ {Offset: 0, Size: 128, Hash: []byte("some foo hash bytes")}, {Offset: 128, Size: 128, Hash: []byte("some other foo hash bytes")}, @@ -180,7 +177,12 @@ func TestFileQueueDone(t *testing.T) { */ func TestFileQueueGetNodeIDs(t *testing.T) { - q := FileQueue{resolver: fakeResolver{}} + q := FileQueue{} + q.SetAvailable("a-foo", "nodeID") + q.AddAvailable("a-foo", "a") + q.SetAvailable("b-bar", "nodeID") + q.AddAvailable("b-bar", "b") + q.Add("a-foo", []Block{ {Offset: 0, Size: 128, Hash: []byte("some foo hash bytes")}, {Offset: 128, Size: 128, Hash: []byte("some other foo hash bytes")}, @@ -252,8 +254,9 @@ func TestFileQueueThreadHandling(t *testing.T) { total += i } - q := FileQueue{resolver: fakeResolver{}} + q := FileQueue{} q.Add("foo", blocks, nil) + q.SetAvailable("foo", "nodeID") var start = make(chan bool) var gotTot uint32 diff --git a/model/model.go b/model/model.go index 09227793..572c980b 100644 --- a/model/model.go +++ b/model/model.go @@ -315,6 +315,7 @@ func (m *Model) Close(node string, err error) { delete(m.remote, node) delete(m.protoConn, node) delete(m.rawConn, node) + m.fq.RemoveAvailable(node) m.recomputeGlobal() m.recomputeNeed() diff --git a/model/model_test.go b/model/model_test.go index 0dd0c54d..8262891a 100644 --- a/model/model_test.go +++ b/model/model_test.go @@ -303,14 +303,21 @@ func TestForgetNode(t *testing.T) { } m.Index("42", []protocol.FileInfo{newFile}) + newFile = protocol.FileInfo{ + Name: "new file 2", + Modified: time.Now().Unix(), + Blocks: []protocol.BlockInfo{{100, []byte("some hash bytes")}}, + } + m.Index("43", []protocol.FileInfo{newFile}) + if l1, l2 := len(m.local), len(fs); l1 != l2 { t.Errorf("Model len(local) incorrect (%d != %d)", l1, l2) } - if l1, l2 := len(m.global), len(fs)+1; l1 != l2 { + if l1, l2 := len(m.global), len(fs)+2; l1 != l2 { t.Errorf("Model len(global) incorrect (%d != %d)", l1, l2) } - if fs, _ := m.NeedFiles(); len(fs) != 1 { - t.Errorf("Model len(need) incorrect (%d != 1)", len(fs)) + if fs, _ := m.NeedFiles(); len(fs) != 2 { + t.Errorf("Model len(need) incorrect (%d != 2)", len(fs)) } m.Close("42", nil) @@ -318,21 +325,13 @@ func TestForgetNode(t *testing.T) { if l1, l2 := len(m.local), len(fs); l1 != l2 { t.Errorf("Model len(local) incorrect (%d != %d)", l1, l2) } - if l1, l2 := len(m.global), len(fs); l1 != l2 { + if l1, l2 := len(m.global), len(fs)+1; l1 != l2 { t.Errorf("Model len(global) incorrect (%d != %d)", l1, l2) } if fs, _ := m.NeedFiles(); len(fs) != 1 { t.Errorf("Model len(need) incorrect (%d != 1)", len(fs)) } - // The file will be removed from the need list when we notice there are no nodes that can provide it - _, ok := m.fq.Get("42") - if ok { - t.Errorf("Unexpected successfull Get()") - } - if fs, _ := m.NeedFiles(); len(fs) != 0 { - t.Errorf("Model len(need) incorrect (%d != 0)", len(fs)) - } } func TestRequest(t *testing.T) {