...

Source file src/scheduler/scheduler/rr_with_master_scheduler.go

Documentation: scheduler/scheduler

     1  /*
     2   * P2PFaaS - A framework for FaaS Load Balancing
     3   * Copyright (c) 2019 - 2022. Gabriele Proietti Mattia <pm.gabriele@outlook.com>
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
    17   */
    18  
    19  package scheduler
    20  
    21  import (
    22  	"fmt"
    23  	"scheduler/log"
    24  	"scheduler/service_discovery"
    25  	"scheduler/types"
    26  	"sync"
    27  	"time"
    28  )
    29  
    30  const RoundRobinWithMasterSchedulerName = "RoundRobinWithMasterScheduler"
    31  
    32  // RoundRobinWithMasterScheduler is a scheduler which implements a round-robin fashion with a master node
    33  type RoundRobinWithMasterScheduler struct {
    34  	// Master tells if the current node is the master node
    35  	Master bool
    36  	// MasterIP stores the IP address of the master node
    37  	MasterIP string
    38  	// Loss tells if tasks are loss when there are no free slots for executing the task in parallel with others
    39  	Loss bool
    40  
    41  	currentIndex      int        // current index of the round-robin
    42  	currentIndexMutex sync.Mutex // protect race conditions on currentIndex
    43  }
    44  
    45  func (s *RoundRobinWithMasterScheduler) GetFullName() string {
    46  	return fmt.Sprintf("%s(%t, %s, %t)", RoundRobinWithMasterSchedulerName, s.Master, s.MasterIP, s.Loss)
    47  }
    48  
    49  func (s *RoundRobinWithMasterScheduler) GetScheduler() *types.SchedulerDescriptor {
    50  	return &types.SchedulerDescriptor{
    51  		Name: RoundRobinWithMasterSchedulerName,
    52  		Parameters: []string{
    53  			fmt.Sprintf("%t", s.Master),
    54  			fmt.Sprintf("%s", s.MasterIP),
    55  			fmt.Sprintf("%t", s.Loss),
    56  		},
    57  	}
    58  }
    59  
    60  func (s *RoundRobinWithMasterScheduler) Schedule(req *types.ServiceRequest) (*JobResult, error) {
    61  	log.Log.Debugf("Scheduling job %s", req.ServiceName)
    62  	now := time.Now()
    63  	timingsStart := types.TimingsStart{ArrivedAt: &now}
    64  
    65  	// Master node
    66  	if s.Master {
    67  		// Master node cannot schedule jobs only dispatch them
    68  		if !req.External {
    69  			return nil, JobCannotBeScheduled{}
    70  		}
    71  		// Obtain the list of all machines and select one with a round robin fashion
    72  		machinesIp, err := service_discovery.GetMachinesIpsList()
    73  		if err != nil {
    74  			return nil, JobCannotBeScheduled{err.Error()}
    75  		}
    76  		if len(machinesIp) == 0 {
    77  			return nil, JobCannotBeScheduled{"no machine known"}
    78  		}
    79  
    80  		// Update the id of next machine
    81  		s.currentIndexMutex.Lock()
    82  		// Check if current index is not exceeding the length of machines array
    83  		if s.currentIndex >= len(machinesIp) {
    84  			s.currentIndex = 0
    85  		}
    86  		pickedMachineIp := machinesIp[s.currentIndex]
    87  		s.currentIndex = (s.currentIndex + 1) % len(machinesIp)
    88  		s.currentIndexMutex.Unlock()
    89  
    90  		log.Log.Debugf("nextIndex is %d", s.currentIndex)
    91  
    92  		// Schedule the job to that machine
    93  		return executeJobExternally(req, pickedMachineIp, &timingsStart, s.GetFullName())
    94  	}
    95  
    96  	// Slave node
    97  	// If request is internal dispatch it to the master node
    98  	if !req.External {
    99  		return executeJobExternally(req, s.MasterIP, &timingsStart, s.GetFullName())
   100  	}
   101  
   102  	// Otherwise execute it internally
   103  	return executeJobLocally(req, &timingsStart, s.GetFullName())
   104  }
   105  

View as plain text