Browse Source

raft: fix freeTo fails to free

If freeTo is called when to is set to the lastest inflight, freeTo
fails to free the slots.
Yicheng Qin 10 years ago
parent
commit
d91ea7f199
2 changed files with 30 additions and 8 deletions
  1. 16 8
      raft/progress.go
  2. 14 0
      raft/progress_test.go

+ 16 - 8
raft/progress.go

@@ -202,17 +202,25 @@ func (in *inflights) add(inflight uint64) {
 
 
 // freeTo frees the inflights smaller or equal to the given `to` flight.
 // freeTo frees the inflights smaller or equal to the given `to` flight.
 func (in *inflights) freeTo(to uint64) {
 func (in *inflights) freeTo(to uint64) {
-	for i := in.start; i < in.start+in.count; i++ {
-		idx := i
-		if i >= in.size {
-			idx -= in.size
-		}
-		if to < in.buffer[idx] {
-			in.count -= i - in.start
-			in.start = idx
+	if in.count == 0 || to < in.buffer[in.start] {
+		// out of the left side of the window
+		return
+	}
+
+	i, idx := 0, in.start
+	for i = 0; i < in.count; i++ {
+		if to < in.buffer[idx] { // found the first large inflight
 			break
 			break
 		}
 		}
+
+		// increase index and maybe rotate
+		if idx += 1; idx >= in.size {
+			idx -= in.size
+		}
 	}
 	}
+	// free i inflights and set new start index
+	in.count -= i
+	in.start = idx
 }
 }
 
 
 func (in *inflights) freeFirstOne() { in.freeTo(in.buffer[in.start]) }
 func (in *inflights) freeFirstOne() { in.freeTo(in.buffer[in.start]) }

+ 14 - 0
raft/progress_test.go

@@ -151,6 +151,20 @@ func TestInflightFreeTo(t *testing.T) {
 	if !reflect.DeepEqual(in, wantIn3) {
 	if !reflect.DeepEqual(in, wantIn3) {
 		t.Fatalf("in = %+v, want %+v", in, wantIn3)
 		t.Fatalf("in = %+v, want %+v", in, wantIn3)
 	}
 	}
+
+	in.freeTo(14)
+
+	wantIn4 := &inflights{
+		start: 5,
+		count: 0,
+		size:  10,
+		//                                   ↓
+		buffer: []uint64{10, 11, 12, 13, 14, 5, 6, 7, 8, 9},
+	}
+
+	if !reflect.DeepEqual(in, wantIn4) {
+		t.Fatalf("in = %+v, want %+v", in, wantIn4)
+	}
 }
 }
 
 
 func TestInflightFreeFirstOne(t *testing.T) {
 func TestInflightFreeFirstOne(t *testing.T) {