-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmachine_assignment.ex
More file actions
100 lines (85 loc) · 3.2 KB
/
machine_assignment.ex
File metadata and controls
100 lines (85 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
defmodule MachineAssignmentExample do
alias BinPacker.OnePerGroupConstraint
alias BinPacker.BallsProportionalToBinObjective
alias BinPacker.EqualNumBallAttributePerBinObjective
defmodule Machine do
defstruct [
:name,
:location,
capacities: Map.new()
]
defimpl BinPacker.Bin do
def id(%@for{location: location, name: name}), do: {location, name}
def attribute(%@for{location: location}, :location), do: location
def attribute(%@for{capacities: capacities}, capacity), do: Map.get(capacities, capacity)
end
end
defmodule Process do
defstruct [
:name,
:service,
:is_leader,
usages: Map.new()
]
defimpl BinPacker.Ball do
def id(%@for{service: service, name: name}), do: {service, name}
def attribute(%@for{service: service}, :service), do: service
def attribute(%@for{is_leader: is_leader}, :is_leader), do: is_leader
def attribute(%@for{usages: usages}, usage), do: Map.get(usages, usage)
end
end
def new do
machines = [
%Machine{name: machine_name(1, 1), location: dc_name(1), capacities: %{cpu: 1500}},
%Machine{name: machine_name(1, 2), location: dc_name(1), capacities: %{cpu: 150}},
%Machine{name: machine_name(2, 1), location: dc_name(2), capacities: %{cpu: 100}},
%Machine{name: machine_name(2, 2), location: dc_name(2), capacities: %{cpu: 100}},
%Machine{name: machine_name(3, 1), location: dc_name(3), capacities: %{cpu: 100}},
%Machine{name: machine_name(3, 2), location: dc_name(3), capacities: %{cpu: 100}},
%Machine{name: machine_name(4, 1), location: dc_name(4), capacities: %{cpu: 100}},
%Machine{name: machine_name(4, 2), location: dc_name(4), capacities: %{cpu: 100}},
%Machine{name: machine_name(5, 1), location: dc_name(5), capacities: %{cpu: 50}},
%Machine{name: machine_name(5, 2), location: dc_name(5), capacities: %{cpu: 50}}
]
processes =
Enum.flat_map(1..9, fn service_num ->
service = "service-#{service_num}"
Enum.map(1..3, fn replica_num ->
%Process{name: "replica-#{replica_num}", service: service, is_leader: replica_num == 1, usages: %{load: 10}}
end)
end)
BinPacker.new(
machines,
processes,
%{
{BallsProportionalToBinObjective, [ball_attribute: :load, bin_attribute: :cpu]} => 1,
{EqualNumBallAttributePerBinObjective, :is_leader} => 1
},
constraints: [
{OnePerGroupConstraint, [ball_attribute: :service, bin_attribute: :location]}
])
end
def add_machine(bin_packer) do
dc_num = Enum.random(1..5)
dc = dc_name(dc_num)
machine_num =
bin_packer
|> BinPacker.to_map()
|> Map.keys()
|> Enum.group_by(fn %Machine{location: location} -> location end)
|> Map.get(dc, [])
|> Enum.count()
|> Kernel.+(1)
machine = %Machine{name: machine_name(dc_num, machine_num), location: dc, capacities: %{cpu: 50}}
BinPacker.add_bin(bin_packer, machine)
end
def optimize(bin_packer) do
BinPacker.search(bin_packer)
end
defp machine_name(dc_num, machine_num) do
"box-#{dc_name(dc_num)}-n#{machine_num}"
end
defp dc_name(dc_num) do
"dc#{dc_num}"
end
end