Sfoglia il codice sorgente

Clear availability for disconnected node

Jakob Borg 12 anni fa
parent
commit
8d5aed410f
4 ha cambiato i file con 57 aggiunte e 29 eliminazioni
  1. 25 0
      model/filequeue.go
  2. 20 17
      model/filequeue_test.go
  3. 1 0
      model/model.go
  4. 11 12
      model/model_test.go

+ 25 - 0
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
+		}
+	}
+}

+ 20 - 17
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

+ 1 - 0
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()

+ 11 - 12
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) {