scheduler concurrent bug fix (#513)
Signed-off-by: santong <weipeng.swp@alibaba-inc.com>
This commit is contained in:
parent
0df064202e
commit
4d49d77d5c
|
|
@ -21,6 +21,7 @@ package config
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"d7y.io/dragonfly/v2/pkg/basic/dfnet"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"d7y.io/dragonfly/v2/client/clientutil"
|
"d7y.io/dragonfly/v2/client/clientutil"
|
||||||
|
|
@ -42,7 +43,12 @@ var peerHostConfig = DaemonOption{
|
||||||
GCInterval: clientutil.Duration{Duration: DefaultGCInterval},
|
GCInterval: clientutil.Duration{Duration: DefaultGCInterval},
|
||||||
KeepStorage: false,
|
KeepStorage: false,
|
||||||
Scheduler: SchedulerOption{
|
Scheduler: SchedulerOption{
|
||||||
NetAddrs: nil,
|
NetAddrs: []dfnet.NetAddr{
|
||||||
|
{
|
||||||
|
Type: dfnet.TCP,
|
||||||
|
Addr: "127.0.0.1:8002",
|
||||||
|
},
|
||||||
|
},
|
||||||
ScheduleTimeout: clientutil.Duration{Duration: DefaultScheduleTimeout},
|
ScheduleTimeout: clientutil.Duration{Duration: DefaultScheduleTimeout},
|
||||||
},
|
},
|
||||||
Host: HostOption{
|
Host: HostOption{
|
||||||
|
|
|
||||||
|
|
@ -684,7 +684,7 @@ func (pt *peerTask) getPieceTasks(span trace.Span, curPeerPacket *scheduler.Peer
|
||||||
if getErr != nil {
|
if getErr != nil {
|
||||||
span.RecordError(getErr)
|
span.RecordError(getErr)
|
||||||
// fast way to exit retry
|
// fast way to exit retry
|
||||||
if curPeerPacket != pt.peerPacket {
|
if curPeerPacket.MainPeer.PeerId != pt.peerPacket.MainPeer.PeerId {
|
||||||
pt.Warnf("get piece tasks with error: %s, but peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s", getErr,
|
pt.Warnf("get piece tasks with error: %s, but peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s", getErr,
|
||||||
curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
|
curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
|
||||||
peerPacketChanged = true
|
peerPacketChanged = true
|
||||||
|
|
@ -709,7 +709,7 @@ func (pt *peerTask) getPieceTasks(span trace.Span, curPeerPacket *scheduler.Peer
|
||||||
pt.Errorf("send piece result error: %s, code: %d", peer.PeerId, er)
|
pt.Errorf("send piece result error: %s, code: %d", peer.PeerId, er)
|
||||||
}
|
}
|
||||||
// fast way to exit retry
|
// fast way to exit retry
|
||||||
if curPeerPacket != pt.peerPacket {
|
if curPeerPacket.MainPeer.PeerId != pt.peerPacket.MainPeer.PeerId {
|
||||||
pt.Warnf("get empty pieces and peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s",
|
pt.Warnf("get empty pieces and peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s",
|
||||||
curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
|
curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
|
||||||
peerPacketChanged = true
|
peerPacketChanged = true
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ func InitMonitor(verbose bool, pprofPort int, jaeger string) func() {
|
||||||
pprofPort, _ = freeport.GetFreePort()
|
pprofPort, _ = freeport.GetFreePort()
|
||||||
}
|
}
|
||||||
|
|
||||||
debugAddr := fmt.Sprintf("localhost:%d", pprofPort)
|
debugAddr := fmt.Sprintf("%s:%d", iputils.HostIP, pprofPort)
|
||||||
viewer.SetConfiguration(viewer.WithAddr(debugAddr))
|
viewer.SetConfiguration(viewer.WithAddr(debugAddr))
|
||||||
|
|
||||||
logger.With("pprof", fmt.Sprintf("http://%s/debug/pprof", debugAddr),
|
logger.With("pprof", fmt.Sprintf("http://%s/debug/pprof", debugAddr),
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,10 @@ func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...st
|
||||||
}
|
}
|
||||||
if selected {
|
if selected {
|
||||||
if client, ok := conn.node2ClientMap.Load(node); ok {
|
if client, ok := conn.node2ClientMap.Load(node); ok {
|
||||||
return client.(*candidateClient), nil
|
return &candidateClient{
|
||||||
|
node: candidateNode,
|
||||||
|
Ref: client,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +229,7 @@ func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...st
|
||||||
if len(ringNodes) == 0 {
|
if len(ringNodes) == 0 {
|
||||||
return nil, dferrors.ErrNoCandidateNode
|
return nil, dferrors.ErrNoCandidateNode
|
||||||
}
|
}
|
||||||
candidateNodes := make([]string, 0, 0)
|
candidateNodes := make([]string, 0)
|
||||||
for _, ringNode := range ringNodes {
|
for _, ringNode := range ringNodes {
|
||||||
candidate := true
|
candidate := true
|
||||||
for _, exclusiveNode := range exclusiveNodes {
|
for _, exclusiveNode := range exclusiveNodes {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package client
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
@ -56,7 +55,7 @@ func newPeerPacketStream(ctx context.Context, sc *schedulerClient, hashKey strin
|
||||||
|
|
||||||
pps := &peerPacketStream{
|
pps := &peerPacketStream{
|
||||||
sc: sc,
|
sc: sc,
|
||||||
ctx: ctx,
|
ctx: context.Background(),
|
||||||
hashKey: hashKey,
|
hashKey: hashKey,
|
||||||
ptr: ptr,
|
ptr: ptr,
|
||||||
opts: opts,
|
opts: opts,
|
||||||
|
|
@ -126,9 +125,9 @@ func (pps *peerPacketStream) retryRecv(cause error) (*scheduler.PeerPacket, erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
timeCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
//timeCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
//defer cancel()
|
||||||
_, err = client.RegisterPeerTask(timeCtx, pps.ptr)
|
_, err = client.RegisterPeerTask(pps.ctx, pps.ptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -198,9 +197,9 @@ func (pps *peerPacketStream) replaceClient(cause error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
timeCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
//timeCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
//defer cancel()
|
||||||
_, err = client.RegisterPeerTask(timeCtx, pps.ptr)
|
_, err = client.RegisterPeerTask(pps.ctx, pps.ptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,7 @@ func (s *state) start() {
|
||||||
s.waitScheduleParentPeerQueue.AddAfter(peer, time.Second)
|
s.waitScheduleParentPeerQueue.AddAfter(peer, time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if peer.PacketChan == nil {
|
peer.SendSchedulePacket(constructSuccessPeerPacket(peer, parent, candidates))
|
||||||
logger.Errorf("waitScheduleParentPeerQueue: there is no packet chan associated with peer %s", peer.PeerID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
peer.PacketChan <- constructSuccessPeerPacket(peer, parent, candidates)
|
|
||||||
logger.WithTaskAndPeerID(peer.Task.TaskID,
|
logger.WithTaskAndPeerID(peer.Task.TaskID,
|
||||||
peer.PeerID).Debugf("waitScheduleParentPeerQueue: peer has left from waitScheduleParentPeerQueue because it has scheduled new parent %v", parent)
|
peer.PeerID).Debugf("waitScheduleParentPeerQueue: peer has left from waitScheduleParentPeerQueue because it has scheduled new parent %v", parent)
|
||||||
s.waitScheduleParentPeerQueue.Done(v)
|
s.waitScheduleParentPeerQueue.Done(v)
|
||||||
|
|
@ -104,15 +100,11 @@ func (e startReportPieceResultEvent) apply(s *state) {
|
||||||
s.waitScheduleParentPeerQueue.AddAfter(e.peer, time.Second)
|
s.waitScheduleParentPeerQueue.AddAfter(e.peer, time.Second)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if e.peer.PacketChan == nil {
|
e.peer.SendSchedulePacket(constructSuccessPeerPacket(e.peer, parent, candidates))
|
||||||
logger.Errorf("start report piece result: there is no packet chan associated with peer %s", e.peer.PeerID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
e.peer.PacketChan <- constructSuccessPeerPacket(e.peer, parent, candidates)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e startReportPieceResultEvent) hashKey() string {
|
func (e startReportPieceResultEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerDownloadPieceSuccessEvent struct {
|
type peerDownloadPieceSuccessEvent struct {
|
||||||
|
|
@ -140,17 +132,13 @@ func (e peerDownloadPieceSuccessEvent) apply(s *state) {
|
||||||
if oldParent != nil {
|
if oldParent != nil {
|
||||||
candidates = append(candidates, oldParent)
|
candidates = append(candidates, oldParent)
|
||||||
}
|
}
|
||||||
if e.peer.PacketChan == nil {
|
|
||||||
logger.Errorf("peerDownloadPieceSuccessEvent: there is no packet chan with peer %s", e.peer.PeerID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO if parentPeer is equal with oldParent, need schedule again ?
|
// TODO if parentPeer is equal with oldParent, need schedule again ?
|
||||||
e.peer.PacketChan <- constructSuccessPeerPacket(e.peer, parentPeer, candidates)
|
e.peer.SendSchedulePacket(constructSuccessPeerPacket(e.peer, parentPeer, candidates))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerDownloadPieceSuccessEvent) hashKey() string {
|
func (e peerDownloadPieceSuccessEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerDownloadPieceFailEvent struct {
|
type peerDownloadPieceFailEvent struct {
|
||||||
|
|
@ -183,7 +171,7 @@ func (e peerDownloadPieceFailEvent) apply(s *state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (e peerDownloadPieceFailEvent) hashKey() string {
|
func (e peerDownloadPieceFailEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerReplaceParentEvent struct {
|
type peerReplaceParentEvent struct {
|
||||||
|
|
@ -191,7 +179,7 @@ type peerReplaceParentEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerReplaceParentEvent) hashKey() string {
|
func (e peerReplaceParentEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerReplaceParentEvent) apply(s *state) {
|
func (e peerReplaceParentEvent) apply(s *state) {
|
||||||
|
|
@ -226,20 +214,13 @@ func (e peerDownloadSuccessEvent) apply(s *state) {
|
||||||
removePeerFromCurrentTree(e.peer, s)
|
removePeerFromCurrentTree(e.peer, s)
|
||||||
children := s.sched.ScheduleChildren(e.peer)
|
children := s.sched.ScheduleChildren(e.peer)
|
||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
if child.PacketChan == nil {
|
child.SendSchedulePacket(constructSuccessPeerPacket(child, e.peer, nil))
|
||||||
logger.Debugf("reportPeerSuccessResult: there is no packet chan with peer %s", e.peer.PeerID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
child.PacketChan <- constructSuccessPeerPacket(child, e.peer, nil)
|
|
||||||
}
|
|
||||||
if e.peer.PacketChan != nil {
|
|
||||||
close(e.peer.PacketChan)
|
|
||||||
e.peer.PacketChan = nil
|
|
||||||
}
|
}
|
||||||
|
e.peer.UnBindSendChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerDownloadSuccessEvent) hashKey() string {
|
func (e peerDownloadSuccessEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerDownloadFailEvent struct {
|
type peerDownloadFailEvent struct {
|
||||||
|
|
@ -260,22 +241,14 @@ func (e peerDownloadFailEvent) apply(s *state) {
|
||||||
s.waitScheduleParentPeerQueue.AddAfter(e.peer, time.Second)
|
s.waitScheduleParentPeerQueue.AddAfter(e.peer, time.Second)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if child.PacketChan == nil {
|
child.SendSchedulePacket(constructSuccessPeerPacket(child, parent, candidates))
|
||||||
logger.Warnf("reportPeerFailResult: there is no packet chan associated with peer %s", e.peer.PeerID)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
child.PacketChan <- constructSuccessPeerPacket(child, parent, candidates)
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if e.peer.PacketChan != nil {
|
|
||||||
close(e.peer.PacketChan)
|
|
||||||
e.peer.PacketChan = nil
|
|
||||||
}
|
|
||||||
s.peerManager.Delete(e.peer.PeerID)
|
s.peerManager.Delete(e.peer.PeerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerDownloadFailEvent) hashKey() string {
|
func (e peerDownloadFailEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerLeaveEvent struct {
|
type peerLeaveEvent struct {
|
||||||
|
|
@ -289,7 +262,7 @@ func (e peerLeaveEvent) apply(s *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e peerLeaveEvent) hashKey() string {
|
func (e peerLeaveEvent) hashKey() string {
|
||||||
return e.peer.PeerID
|
return e.peer.Task.TaskID
|
||||||
}
|
}
|
||||||
|
|
||||||
func constructSuccessPeerPacket(peer *types.Peer, parent *types.Peer, candidates []*types.Peer) *schedulerRPC.PeerPacket {
|
func constructSuccessPeerPacket(peer *types.Peer, parent *types.Peer, candidates []*types.Peer) *schedulerRPC.PeerPacket {
|
||||||
|
|
@ -337,11 +310,7 @@ func handlePeerLeave(peer *types.Peer, s *state) {
|
||||||
s.waitScheduleParentPeerQueue.AddAfter(child, time.Second)
|
s.waitScheduleParentPeerQueue.AddAfter(child, time.Second)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if child.PacketChan == nil {
|
child.SendSchedulePacket(constructSuccessPeerPacket(child, parent, candidates))
|
||||||
logger.Debugf("handlePeerLeave: there is no packet chan with peer %s", child.PeerID)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
child.PacketChan <- constructSuccessPeerPacket(child, parent, candidates)
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
s.peerManager.Delete(peer.PeerID)
|
s.peerManager.Delete(peer.PeerID)
|
||||||
|
|
@ -355,22 +324,14 @@ func handleReplaceParent(peer *types.Peer, s *state) {
|
||||||
s.waitScheduleParentPeerQueue.AddAfter(peer, time.Second)
|
s.waitScheduleParentPeerQueue.AddAfter(peer, time.Second)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if peer.PacketChan == nil {
|
peer.SendSchedulePacket(constructSuccessPeerPacket(peer, parent, candidates))
|
||||||
logger.Errorf("handleReplaceParent: there is no packet chan with peer %s", peer.PeerID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
peer.PacketChan <- constructSuccessPeerPacket(peer, parent, candidates)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSeedTaskFail(task *types.Task) {
|
func handleSeedTaskFail(task *types.Task) {
|
||||||
if task.IsFail() {
|
if task.IsFail() {
|
||||||
task.ListPeers().Range(func(data sortedlist.Item) bool {
|
task.ListPeers().Range(func(data sortedlist.Item) bool {
|
||||||
peer := data.(*types.Peer)
|
peer := data.(*types.Peer)
|
||||||
if peer.PacketChan == nil {
|
peer.SendSchedulePacket(constructFailPeerPacket(peer, dfcodes.CdnError))
|
||||||
logger.Debugf("taskSeedFailEvent: there is no packet chan with peer %s", peer.PeerID)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
peer.PacketChan <- constructFailPeerPacket(peer, dfcodes.CdnError)
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -383,11 +344,7 @@ func removePeerFromCurrentTree(peer *types.Peer, s *state) {
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
children := s.sched.ScheduleChildren(parent)
|
children := s.sched.ScheduleChildren(parent)
|
||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
if child.PacketChan == nil {
|
child.SendSchedulePacket(constructSuccessPeerPacket(child, peer, nil))
|
||||||
logger.Debugf("removePeerFromCurrentTree: there is no packet chan with peer %s", peer.PeerID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
child.PacketChan <- constructSuccessPeerPacket(child, peer, nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ func (m *monitor) printDebugInfo() string {
|
||||||
parentNode = peer.GetParent().PeerID
|
parentNode = peer.GetParent().PeerID
|
||||||
}
|
}
|
||||||
|
|
||||||
table.Append([]string{peer.PeerID, peer.Task.URL[len(peer.Task.URL)-15 : len(peer.Task.URL)-5], parentNode, peer.GetStatus().String(),
|
table.Append([]string{peer.PeerID, peer.Task.URL[len(peer.Task.URL)-15 : len(peer.Task.URL)], parentNode, peer.GetStatus().String(),
|
||||||
peer.CreateTime.String(),
|
peer.CreateTime.String(),
|
||||||
strconv.Itoa(int(peer.GetFinishedNum())),
|
strconv.Itoa(int(peer.GetFinishedNum())),
|
||||||
strconv.FormatBool(peer.IsSuccess()), strconv.Itoa(peer.Host.GetFreeUploadLoad())})
|
strconv.FormatBool(peer.IsSuccess()), strconv.Itoa(peer.Host.GetFreeUploadLoad())})
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,9 @@ func (s *SchedulerService) GetOrCreateTask(ctx context.Context, task *types.Task
|
||||||
if task.IsFrozen() {
|
if task.IsFrozen() {
|
||||||
task.SetStatus(types.TaskStatusRunning)
|
task.SetStatus(types.TaskStatusRunning)
|
||||||
}
|
}
|
||||||
|
//if s.config.DisableCDN {
|
||||||
|
// TODO NeedBackSource
|
||||||
|
//}
|
||||||
go func() {
|
go func() {
|
||||||
if err := s.cdnManager.StartSeedTask(ctx, task); err != nil {
|
if err := s.cdnManager.StartSeedTask(ctx, task); err != nil {
|
||||||
if !task.IsSuccess() {
|
if !task.IsSuccess() {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ func (wg *workerGroup) send(e event) bool {
|
||||||
|
|
||||||
func (wg *workerGroup) stop() {
|
func (wg *workerGroup) stop() {
|
||||||
close(wg.stopCh)
|
close(wg.stopCh)
|
||||||
wg.s.start()
|
wg.s.stop()
|
||||||
for _, worker := range wg.workerList {
|
for _, worker := range wg.workerList {
|
||||||
worker.stop()
|
worker.stop()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func (cm *manager) StartSeedTask(ctx context.Context, task *types.Task) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *manager) receivePiece(task *types.Task, stream *client.PieceSeedStream) error {
|
func (cm *manager) receivePiece(task *types.Task, stream *client.PieceSeedStream) error {
|
||||||
var once sync.Once
|
var initialized bool
|
||||||
var cdnPeer *types.Peer
|
var cdnPeer *types.Peer
|
||||||
for {
|
for {
|
||||||
piece, err := stream.Recv()
|
piece, err := stream.Recv()
|
||||||
|
|
@ -138,9 +138,10 @@ func (cm *manager) receivePiece(task *types.Task, stream *client.PieceSeedStream
|
||||||
return errors.Wrapf(ErrCDNInvokeFail, "receive piece from cdn: %v", err)
|
return errors.Wrapf(ErrCDNInvokeFail, "receive piece from cdn: %v", err)
|
||||||
}
|
}
|
||||||
if piece != nil {
|
if piece != nil {
|
||||||
once.Do(func() {
|
if !initialized {
|
||||||
cdnPeer, err = cm.initCdnPeer(task, piece)
|
cdnPeer, err = cm.initCdnPeer(task, piece)
|
||||||
})
|
initialized = true
|
||||||
|
}
|
||||||
if err != nil || cdnPeer == nil {
|
if err != nil || cdnPeer == nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,7 @@ func (m *manager) Delete(peerID string) {
|
||||||
if ok {
|
if ok {
|
||||||
peer.Host.DeletePeer(peerID)
|
peer.Host.DeletePeer(peerID)
|
||||||
peer.Task.DeletePeer(peer)
|
peer.Task.DeletePeer(peer)
|
||||||
if peer.PacketChan != nil {
|
peer.UnBindSendChannel()
|
||||||
close(peer.PacketChan)
|
|
||||||
logger.Infof("close peer %s stream", peerID)
|
|
||||||
peer.PacketChan = nil
|
|
||||||
}
|
|
||||||
m.peerMap.Delete(peerID)
|
m.peerMap.Delete(peerID)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ import (
|
||||||
"d7y.io/dragonfly/v2/scheduler/core"
|
"d7y.io/dragonfly/v2/scheduler/core"
|
||||||
"d7y.io/dragonfly/v2/scheduler/types"
|
"d7y.io/dragonfly/v2/scheduler/types"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SchedulerServer struct {
|
type SchedulerServer struct {
|
||||||
|
|
@ -118,24 +120,33 @@ func (s *SchedulerServer) RegisterPeerTask(ctx context.Context, request *schedul
|
||||||
|
|
||||||
func (s *SchedulerServer) ReportPieceResult(stream scheduler.Scheduler_ReportPieceResultServer) error {
|
func (s *SchedulerServer) ReportPieceResult(stream scheduler.Scheduler_ReportPieceResultServer) error {
|
||||||
peerPacketChan := make(chan *scheduler.PeerPacket, 1)
|
peerPacketChan := make(chan *scheduler.PeerPacket, 1)
|
||||||
|
var peer *types.Peer
|
||||||
|
var initialized bool
|
||||||
|
ctx, cancel := context.WithCancel(stream.Context())
|
||||||
|
g, ctx := errgroup.WithContext(ctx)
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
g, ctx := errgroup.WithContext(context.Background())
|
|
||||||
stopCh := make(chan struct{})
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
once.Do(peer.UnBindSendChannel)
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
var peer *types.Peer
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return nil
|
||||||
case <-stopCh:
|
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
pieceResult, err := stream.Recv()
|
pieceResult, err := stream.Recv()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dferrors.Newf(dfcodes.SchedPeerPieceResultReportFail, "peer piece result report error")
|
if status.Code(err) == codes.Canceled {
|
||||||
|
if peer != nil {
|
||||||
|
logger.Info("peer %s canceled", peer.PeerID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dferrors.Newf(dfcodes.SchedPeerPieceResultReportFail, "peer piece result report error: %v", err)
|
||||||
}
|
}
|
||||||
logger.Debugf("report piece result %v of peer %s", pieceResult, pieceResult.SrcPid)
|
logger.Debugf("report piece result %v of peer %s", pieceResult, pieceResult.SrcPid)
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
@ -143,10 +154,11 @@ func (s *SchedulerServer) ReportPieceResult(stream scheduler.Scheduler_ReportPie
|
||||||
if !ok {
|
if !ok {
|
||||||
return dferrors.Newf(dfcodes.SchedPeerNotFound, "peer %s not found", pieceResult.SrcPid)
|
return dferrors.Newf(dfcodes.SchedPeerNotFound, "peer %s not found", pieceResult.SrcPid)
|
||||||
}
|
}
|
||||||
once.Do(func() {
|
if !initialized {
|
||||||
peer.BindSendChannel(peerPacketChan)
|
peer.BindSendChannel(peerPacketChan)
|
||||||
peer.SetStatus(types.PeerStatusRunning)
|
peer.SetStatus(types.PeerStatusRunning)
|
||||||
})
|
initialized = true
|
||||||
|
}
|
||||||
if err := s.service.HandlePieceResult(peer, pieceResult); err != nil {
|
if err := s.service.HandlePieceResult(peer, pieceResult); err != nil {
|
||||||
logger.Errorf("handle piece result %v fail: %v", pieceResult, err)
|
logger.Errorf("handle piece result %v fail: %v", pieceResult, err)
|
||||||
}
|
}
|
||||||
|
|
@ -155,21 +167,22 @@ func (s *SchedulerServer) ReportPieceResult(stream scheduler.Scheduler_ReportPie
|
||||||
})
|
})
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
once.Do(peer.UnBindSendChannel)
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return nil
|
||||||
case <-stopCh:
|
|
||||||
return nil
|
|
||||||
case pp, ok := <-peerPacketChan:
|
case pp, ok := <-peerPacketChan:
|
||||||
if !ok {
|
if !ok {
|
||||||
close(stopCh)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := stream.Send(pp)
|
err := stream.Send(pp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("send peer %s schedule packet %v failed: %v", pp.SrcPid, pp, err)
|
logger.Errorf("send peer %s schedule packet %v failed: %v", pp.SrcPid, pp, err)
|
||||||
return err
|
return dferrors.Newf(dfcodes.SchedPeerPieceResultReportFail, "peer piece result report error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,10 @@ type Peer struct {
|
||||||
Task *Task
|
Task *Task
|
||||||
// Host specifies
|
// Host specifies
|
||||||
Host *PeerHost
|
Host *PeerHost
|
||||||
|
// bindPacketChan
|
||||||
|
bindPacketChan bool
|
||||||
// PacketChan send schedulerPacket to peer client
|
// PacketChan send schedulerPacket to peer client
|
||||||
PacketChan chan *scheduler.PeerPacket
|
packetChan chan *scheduler.PeerPacket
|
||||||
// createTime
|
// createTime
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
// finishedNum specifies downloaded finished piece number
|
// finishedNum specifies downloaded finished piece number
|
||||||
|
|
@ -293,11 +295,27 @@ func (peer *Peer) SetStatus(status PeerStatus) {
|
||||||
func (peer *Peer) BindSendChannel(packetChan chan *scheduler.PeerPacket) {
|
func (peer *Peer) BindSendChannel(packetChan chan *scheduler.PeerPacket) {
|
||||||
peer.lock.Lock()
|
peer.lock.Lock()
|
||||||
defer peer.lock.Unlock()
|
defer peer.lock.Unlock()
|
||||||
peer.PacketChan = packetChan
|
peer.bindPacketChan = true
|
||||||
|
peer.packetChan = packetChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func (peer *Peer) GetSendChannel() chan *scheduler.PeerPacket {
|
func (peer *Peer) UnBindSendChannel() {
|
||||||
return peer.PacketChan
|
peer.lock.Lock()
|
||||||
|
defer peer.lock.Unlock()
|
||||||
|
if peer.bindPacketChan {
|
||||||
|
if peer.packetChan != nil {
|
||||||
|
close(peer.packetChan)
|
||||||
|
}
|
||||||
|
peer.bindPacketChan = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (peer *Peer) SendSchedulePacket(packet *scheduler.PeerPacket) {
|
||||||
|
peer.lock.Lock()
|
||||||
|
defer peer.lock.Unlock()
|
||||||
|
if peer.bindPacketChan {
|
||||||
|
peer.packetChan <- packet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (peer *Peer) IsRunning() bool {
|
func (peer *Peer) IsRunning() bool {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue