From 2a03a4d502095f09520e666b32b88e1549a1ee0d Mon Sep 17 00:00:00 2001 From: Kouhei Ueno Date: Sat, 12 Jul 2014 15:06:36 +0900 Subject: [PATCH 1/3] make random.go threadsafe --- pkg/scheduler/random.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/scheduler/random.go b/pkg/scheduler/random.go index 23a076636a8..6cf0e9057bc 100644 --- a/pkg/scheduler/random.go +++ b/pkg/scheduler/random.go @@ -18,14 +18,15 @@ package scheduler import ( "math/rand" + "sync" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) // RandomScheduler chooses machines uniformly at random. type RandomScheduler struct { - // TODO: rand.Rand is *NOT* thread safe. - random *rand.Rand + random *rand.Rand + randomLock sync.Mutex } func MakeRandomScheduler(random *rand.Rand) Scheduler { @@ -40,5 +41,8 @@ func (s *RandomScheduler) Schedule(pod api.Pod, minionLister MinionLister) (stri if err != nil { return "", err } + + s.randomLock.Lock() + defer s.randomLock.Unlock() return machines[s.random.Int()%len(machines)], nil } From 070b4ffe9f9960b5f06efa68c48b0ef09cdd52dd Mon Sep 17 00:00:00 2001 From: Kouhei Ueno Date: Sat, 12 Jul 2014 15:06:51 +0900 Subject: [PATCH 2/3] make firstfit.go threadsafe and fix its comments --- pkg/scheduler/firstfit.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/scheduler/firstfit.go b/pkg/scheduler/firstfit.go index e1e088c5cc4..250fa99faf1 100644 --- a/pkg/scheduler/firstfit.go +++ b/pkg/scheduler/firstfit.go @@ -19,16 +19,17 @@ package scheduler import ( "fmt" "math/rand" + "sync" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" ) -// FirstFitScheduler is a Scheduler interface implementation which uses first fit algorithm. +// FirstFitScheduler is a Scheduler which schedules a Pod on a random machine which matches its requirement. type FirstFitScheduler struct { - podLister PodLister - // TODO: *rand.Rand is *not* threadsafe - random *rand.Rand + podLister PodLister + random *rand.Rand + randomLock sync.Mutex } func MakeFirstFitScheduler(podLister PodLister, random *rand.Rand) Scheduler { @@ -49,7 +50,7 @@ func (s *FirstFitScheduler) containsPort(pod api.Pod, port api.Port) bool { return false } -// Schedule schedules a pod on the first machine which matches its requirement. +// Schedule schedules a pod on a random machine which matches its requirement. func (s *FirstFitScheduler) Schedule(pod api.Pod, minionLister MinionLister) (string, error) { machines, err := minionLister.List() if err != nil { @@ -83,5 +84,7 @@ func (s *FirstFitScheduler) Schedule(pod api.Pod, minionLister MinionLister) (st if len(machineOptions) == 0 { return "", fmt.Errorf("failed to find fit for %#v", pod) } + s.randomLock.Lock() + defer s.randomLock.Unlock() return machineOptions[s.random.Int()%len(machineOptions)], nil } From c875a6d3ba1e9ebe74fe20448da9be4745337e98 Mon Sep 17 00:00:00 2001 From: Kouhei Ueno Date: Sat, 12 Jul 2014 23:14:39 +0900 Subject: [PATCH 3/3] rename FirstFitScheduler to RandomFitScheduler --- pkg/master/master.go | 2 +- pkg/scheduler/{firstfit.go => randomfit.go} | 12 ++++++------ .../{firstfit_test.go => randomfit_test.go} | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) rename pkg/scheduler/{firstfit.go => randomfit.go} (83%) rename pkg/scheduler/{firstfit_test.go => randomfit_test.go} (78%) diff --git a/pkg/master/master.go b/pkg/master/master.go index 80831fa095e..74c40d0081b 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -84,7 +84,7 @@ func (m *Master) init(cloud cloudprovider.Interface, podInfoGetter client.PodInf m.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) podCache := NewPodCache(podInfoGetter, m.podRegistry, time.Second*30) go podCache.Loop() - s := scheduler.MakeFirstFitScheduler(m.podRegistry, m.random) + s := scheduler.MakeRandomFitScheduler(m.podRegistry, m.random) m.storage = map[string]apiserver.RESTStorage{ "pods": registry.MakePodRegistryStorage(m.podRegistry, podInfoGetter, s, m.minionRegistry, cloud, podCache), "replicationControllers": registry.NewControllerRegistryStorage(m.controllerRegistry, m.podRegistry), diff --git a/pkg/scheduler/firstfit.go b/pkg/scheduler/randomfit.go similarity index 83% rename from pkg/scheduler/firstfit.go rename to pkg/scheduler/randomfit.go index 250fa99faf1..20193fde255 100644 --- a/pkg/scheduler/firstfit.go +++ b/pkg/scheduler/randomfit.go @@ -25,21 +25,21 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" ) -// FirstFitScheduler is a Scheduler which schedules a Pod on a random machine which matches its requirement. -type FirstFitScheduler struct { +// RandomFitScheduler is a Scheduler which schedules a Pod on a random machine which matches its requirement. +type RandomFitScheduler struct { podLister PodLister random *rand.Rand randomLock sync.Mutex } -func MakeFirstFitScheduler(podLister PodLister, random *rand.Rand) Scheduler { - return &FirstFitScheduler{ +func MakeRandomFitScheduler(podLister PodLister, random *rand.Rand) Scheduler { + return &RandomFitScheduler{ podLister: podLister, random: random, } } -func (s *FirstFitScheduler) containsPort(pod api.Pod, port api.Port) bool { +func (s *RandomFitScheduler) containsPort(pod api.Pod, port api.Port) bool { for _, container := range pod.DesiredState.Manifest.Containers { for _, podPort := range container.Ports { if podPort.HostPort == port.HostPort { @@ -51,7 +51,7 @@ func (s *FirstFitScheduler) containsPort(pod api.Pod, port api.Port) bool { } // Schedule schedules a pod on a random machine which matches its requirement. -func (s *FirstFitScheduler) Schedule(pod api.Pod, minionLister MinionLister) (string, error) { +func (s *RandomFitScheduler) Schedule(pod api.Pod, minionLister MinionLister) (string, error) { machines, err := minionLister.List() if err != nil { return "", err diff --git a/pkg/scheduler/firstfit_test.go b/pkg/scheduler/randomfit_test.go similarity index 78% rename from pkg/scheduler/firstfit_test.go rename to pkg/scheduler/randomfit_test.go index 57e8444b0e1..1cdf505b9e1 100644 --- a/pkg/scheduler/firstfit_test.go +++ b/pkg/scheduler/randomfit_test.go @@ -23,31 +23,31 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) -func TestFirstFitSchedulerNothingScheduled(t *testing.T) { +func TestRandomFitSchedulerNothingScheduled(t *testing.T) { fakeRegistry := FakePodLister{} r := rand.New(rand.NewSource(0)) st := schedulerTester{ t: t, - scheduler: MakeFirstFitScheduler(&fakeRegistry, r), + scheduler: MakeRandomFitScheduler(&fakeRegistry, r), minionLister: FakeMinionLister{"m1", "m2", "m3"}, } st.expectSchedule(api.Pod{}, "m3") } -func TestFirstFitSchedulerFirstScheduled(t *testing.T) { +func TestRandomFitSchedulerFirstScheduled(t *testing.T) { fakeRegistry := FakePodLister{ makePod("m1", 8080), } r := rand.New(rand.NewSource(0)) st := schedulerTester{ t: t, - scheduler: MakeFirstFitScheduler(fakeRegistry, r), + scheduler: MakeRandomFitScheduler(fakeRegistry, r), minionLister: FakeMinionLister{"m1", "m2", "m3"}, } st.expectSchedule(makePod("", 8080), "m3") } -func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) { +func TestRandomFitSchedulerFirstScheduledComplicated(t *testing.T) { fakeRegistry := FakePodLister{ makePod("m1", 80, 8080), makePod("m2", 8081, 8082, 8083), @@ -56,13 +56,13 @@ func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) { r := rand.New(rand.NewSource(0)) st := schedulerTester{ t: t, - scheduler: MakeFirstFitScheduler(fakeRegistry, r), + scheduler: MakeRandomFitScheduler(fakeRegistry, r), minionLister: FakeMinionLister{"m1", "m2", "m3"}, } st.expectSchedule(makePod("", 8080, 8081), "m3") } -func TestFirstFitSchedulerFirstScheduledImpossible(t *testing.T) { +func TestRandomFitSchedulerFirstScheduledImpossible(t *testing.T) { fakeRegistry := FakePodLister{ makePod("m1", 8080), makePod("m2", 8081), @@ -71,7 +71,7 @@ func TestFirstFitSchedulerFirstScheduledImpossible(t *testing.T) { r := rand.New(rand.NewSource(0)) st := schedulerTester{ t: t, - scheduler: MakeFirstFitScheduler(fakeRegistry, r), + scheduler: MakeRandomFitScheduler(fakeRegistry, r), minionLister: FakeMinionLister{"m1", "m2", "m3"}, } st.expectFailure(makePod("", 8080, 8081))