Repository: dragonflyoss/Dragonfly2
Pull request #1756 (2022-10-13 10:09:01)

feat: available peer includes state is PeerStatePending
Signed-off-by: Gaius <gaius.qi@gmail.com>

<!--- Provide a general summary of your changes in the Title above -->

## Description
- Available peer includes state is PeerStatePending.
<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## Screenshots (if appropriate)

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation Update (if none of the other choices apply)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.



Patch:
diff --git a/scheduler/resource/task.go b/scheduler/resource/task.go
index c61dee61..21c61693 100644
--- a/scheduler/resource/task.go
+++ b/scheduler/resource/task.go
@@ -330,8 +330,9 @@ func (t *Task) HasAvailablePeer() bool {
 			continue
 		}
 
-		if peer.FSM.Is(PeerStateSucceeded) ||
+		if peer.FSM.Is(PeerStatePending) ||
 			peer.FSM.Is(PeerStateRunning) ||
+			peer.FSM.Is(PeerStateSucceeded) ||
 			peer.FSM.Is(PeerStateBackToSource) {
 			hasAvailablePeer = true
 			break
diff --git a/scheduler/service/service.go b/scheduler/service/service.go
index 337a6d62..2404d745 100644
--- a/scheduler/service/service.go
+++ b/scheduler/service/service.go
@@ -540,8 +540,7 @@ func (s *Service) registerTask(ctx context.Context, req *schedulerv1.PeerTaskReq
 		task.URL = req.Url
 		task.URLMeta = req.UrlMeta
 
-		if !task.FSM.Is(resource.TaskStateFailed) &&
-			!task.FSM.Is(resource.TaskStateLeave) && task.HasAvailablePeer() {
+		if (task.FSM.Is(resource.TaskStatePending) || task.FSM.Is(resource.TaskStateRunning) || task.FSM.Is(resource.TaskStateSucceeded)) && task.HasAvailablePeer() {
 			task.Log.Infof("task dose not need to back-to-source, because of task has available peer and state is %s", task.FSM.Current())
 			return task, false
 		}
@@ -551,14 +550,11 @@ func (s *Service) registerTask(ctx context.Context, req *schedulerv1.PeerTaskReq
 		s.resource.TaskManager().Store(task)
 	}
 
-	// Task state is TaskStateRunning can be registered,
-	// which will cause if the seed peer does not return begin of piece,
-	// the concurrent download of the peer may trigger multiple seed peer downloads.
-	if !task.FSM.Is(resource.TaskStateRunning) {
-		if err := task.FSM.Event(resource.TaskEventDownload); err != nil {
-			task.Log.Errorf("task needs to back-to-source, because of %s", err.Error())
-			return task, true
-		}
+	// If the task triggers the TaskEventDownload failed and it has no available peer,
+	// let the peer do the scheduling.
+	if err := task.FSM.Event(resource.TaskEventDownload); err != nil {
+		task.Log.Warnf("task dose not need to back-to-source, because of %s", err.Error())
+		return task, false
 	}
 
 	// Seed peer registers the task, then it needs to back-to-source.


Test patch:
diff --git a/scheduler/resource/task_test.go b/scheduler/resource/task_test.go
index 6443d47f..20eccdb4 100644
--- a/scheduler/resource/task_test.go
+++ b/scheduler/resource/task_test.go
@@ -905,6 +905,21 @@ func TestTask_HasAvailablePeer(t *testing.T) {
 		backToSourceLimit int32
 		expect            func(t *testing.T, task *Task, mockPeer *Peer)
 	}{
+		{
+			name:              "peer state is PeerStatePending",
+			id:                mockTaskID,
+			urlMeta:           mockTaskURLMeta,
+			url:               mockTaskURL,
+			backToSourceLimit: mockTaskBackToSourceLimit,
+			expect: func(t *testing.T, task *Task, mockPeer *Peer) {
+				assert := assert.New(t)
+				task.StorePeer(mockPeer)
+				mockPeer.ID = idgen.PeerID("0.0.0.0")
+				mockPeer.FSM.SetState(PeerStatePending)
+				task.StorePeer(mockPeer)
+				assert.Equal(task.HasAvailablePeer(), true)
+			},
+		},
 		{
 			name:              "peer state is PeerStateSucceeded",
 			id:                mockTaskID,
diff --git a/scheduler/service/service_test.go b/scheduler/service/service_test.go
index 4bd8d2a1..be978847 100644
--- a/scheduler/service/service_test.go
+++ b/scheduler/service/service_test.go
@@ -1900,18 +1900,10 @@ func TestService_registerTask(t *testing.T) {
 				},
 			},
 			run: func(t *testing.T, svc *Service, req *schedulerv1.PeerTaskRequest, mockTask *resource.Task, mockPeer *resource.Peer, taskManager resource.TaskManager, hostManager resource.HostManager, seedPeer resource.SeedPeer, mr *resource.MockResourceMockRecorder, mt *resource.MockTaskManagerMockRecorder, mh *resource.MockHostManagerMockRecorder, mc *resource.MockSeedPeerMockRecorder) {
-				var wg sync.WaitGroup
-				wg.Add(2)
-				defer wg.Wait()
-
 				mockTask.FSM.SetState(resource.TaskStateRunning)
 				gomock.InOrder(
 					mr.TaskManager().Return(taskManager).Times(1),
 					mt.Load(gomock.Any()).Return(mockTask, true).Times(1),
-					mr.HostManager().Return(hostManager).Times(1),
-					mh.Load(gomock.Any()).Return(nil, false),
-					mr.SeedPeer().Do(func() { wg.Done() }).Return(seedPeer).Times(1),
-					mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(mockPeer, &schedulerv1.PeerResult{}, nil).Times(1),
 				)
 
 				task, needBackToSource := svc.registerTask(context.Background(), req)