@@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
5
5
use super :: model_trait:: { AsModel , SerializableModel } ;
6
6
use super :: ModelMessage ;
7
7
use crate :: simulator:: Services ;
8
+ use crate :: utils:: default_records_port_name;
8
9
use crate :: utils:: error:: SimulationError ;
9
- use crate :: utils:: { populate_history_port, populate_snapshot_port} ;
10
10
11
11
use sim_derive:: SerializableModel ;
12
12
@@ -18,106 +18,155 @@ pub struct LoadBalancer {
18
18
ports_in : PortsIn ,
19
19
ports_out : PortsOut ,
20
20
#[ serde( default ) ]
21
- state : State ,
22
- #[ serde( default ) ]
23
- snapshot : Metrics ,
21
+ store_records : bool ,
24
22
#[ serde( default ) ]
25
- history : Vec < Metrics > ,
23
+ state : State ,
26
24
}
27
25
28
26
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
29
27
struct PortsIn {
30
28
job : String ,
31
- snapshot : Option < String > ,
32
- history : Option < String > ,
29
+ # [ serde ( default = "default_records_port_name" ) ]
30
+ records : String ,
33
31
}
34
32
35
33
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
36
34
#[ serde( rename_all = "camelCase" ) ]
37
35
struct PortsOut {
38
36
flow_paths : Vec < String > ,
39
- snapshot : Option < String > ,
40
- history : Option < String > ,
37
+ # [ serde ( default = "default_records_port_name" ) ]
38
+ records : String ,
41
39
}
42
40
43
41
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
44
42
#[ serde( rename_all = "camelCase" ) ]
45
43
struct State {
46
- event_list : Vec < ScheduledEvent > ,
47
- jobs : Vec < String > ,
44
+ phase : Phase ,
45
+ until_next_event : f64 ,
48
46
next_port_out : usize ,
47
+ jobs : Vec < Job > ,
48
+ records : Vec < Job > ,
49
49
}
50
50
51
51
impl Default for State {
52
52
fn default ( ) -> Self {
53
- let initalization_event = ScheduledEvent {
54
- time : 0.0 ,
55
- event : Event :: Run ,
56
- } ;
57
- State {
58
- event_list : vec ! [ initalization_event] ,
59
- jobs : Vec :: new ( ) ,
53
+ Self {
54
+ phase : Phase :: LoadBalancing ,
55
+ until_next_event : 0.0 ,
60
56
next_port_out : 0 ,
57
+ jobs : Vec :: new ( ) ,
58
+ records : Vec :: new ( ) ,
61
59
}
62
60
}
63
61
}
64
62
65
- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
66
- enum Event {
67
- Run ,
68
- SendJob ,
69
- }
70
-
71
- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
72
- struct ScheduledEvent {
73
- time : f64 ,
74
- event : Event ,
63
+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
64
+ enum Phase {
65
+ LoadBalancing ,
66
+ RecordsFetch ,
75
67
}
76
68
77
69
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
78
70
#[ serde( rename_all = "camelCase" ) ]
79
- struct Metrics {
80
- last_job : Option < ( String , String , f64 ) > , // Port, message, time
81
- }
82
-
83
- impl Default for Metrics {
84
- fn default ( ) -> Self {
85
- Metrics { last_job : None }
86
- }
71
+ struct Job {
72
+ content : String ,
73
+ time : f64 ,
74
+ port_out : String ,
87
75
}
88
76
89
77
impl LoadBalancer {
90
- pub fn new (
91
- job_port : String ,
92
- flow_path_ports : Vec < String > ,
93
- snapshot_metrics : bool ,
94
- history_metrics : bool ,
95
- ) -> Self {
78
+ pub fn new ( job_port : String , flow_path_ports : Vec < String > , store_records : bool ) -> Self {
96
79
Self {
97
80
ports_in : PortsIn {
98
81
job : job_port,
99
- snapshot : populate_snapshot_port ( snapshot_metrics) ,
100
- history : populate_history_port ( history_metrics) ,
82
+ records : default_records_port_name ( ) ,
101
83
} ,
102
84
ports_out : PortsOut {
103
85
flow_paths : flow_path_ports,
104
- snapshot : populate_snapshot_port ( snapshot_metrics) ,
105
- history : populate_history_port ( history_metrics) ,
86
+ records : default_records_port_name ( ) ,
106
87
} ,
88
+ store_records,
107
89
state : Default :: default ( ) ,
108
- snapshot : Default :: default ( ) ,
109
- history : Default :: default ( ) ,
110
90
}
111
91
}
112
92
113
- fn need_snapshot_metrics ( & self ) -> bool {
114
- self . ports_in . snapshot . is_some ( ) && self . ports_out . snapshot . is_some ( )
93
+ fn request_records (
94
+ & mut self ,
95
+ _incoming_message : & ModelMessage ,
96
+ _services : & mut Services ,
97
+ ) -> Result < ( ) , SimulationError > {
98
+ self . state . phase = Phase :: RecordsFetch ;
99
+ self . state . until_next_event = 0.0 ;
100
+ Ok ( ( ) )
115
101
}
116
102
117
- fn need_historical_metrics ( & self ) -> bool {
118
- self . need_snapshot_metrics ( )
119
- && self . ports_in . history . is_some ( )
120
- && self . ports_out . history . is_some ( )
103
+ fn ignore_request (
104
+ & mut self ,
105
+ _incoming_message : & ModelMessage ,
106
+ _services : & mut Services ,
107
+ ) -> Result < ( ) , SimulationError > {
108
+ Ok ( ( ) )
109
+ }
110
+
111
+ fn pass_job (
112
+ & mut self ,
113
+ incoming_message : & ModelMessage ,
114
+ services : & mut Services ,
115
+ ) -> Result < ( ) , SimulationError > {
116
+ self . state . phase = Phase :: LoadBalancing ;
117
+ self . state . until_next_event = 0.0 ;
118
+ self . state . jobs . push ( Job {
119
+ content : incoming_message. content . clone ( ) ,
120
+ time : services. global_time ( ) ,
121
+ port_out : self . ports_out . flow_paths [ self . state . next_port_out ] . clone ( ) ,
122
+ } ) ;
123
+ self . state . next_port_out = ( self . state . next_port_out + 1 ) % self . ports_out . flow_paths . len ( ) ;
124
+ Ok ( ( ) )
125
+ }
126
+
127
+ fn save_job (
128
+ & mut self ,
129
+ incoming_message : & ModelMessage ,
130
+ services : & mut Services ,
131
+ ) -> Result < ( ) , SimulationError > {
132
+ self . state . phase = Phase :: LoadBalancing ;
133
+ self . state . until_next_event = 0.0 ;
134
+ self . state . jobs . push ( Job {
135
+ content : incoming_message. content . clone ( ) ,
136
+ time : services. global_time ( ) ,
137
+ port_out : self . ports_out . flow_paths [ self . state . next_port_out ] . clone ( ) ,
138
+ } ) ;
139
+ self . state . records . push ( Job {
140
+ content : incoming_message. content . clone ( ) ,
141
+ time : services. global_time ( ) ,
142
+ port_out : self . ports_out . flow_paths [ self . state . next_port_out ] . clone ( ) ,
143
+ } ) ;
144
+ self . state . next_port_out = ( self . state . next_port_out + 1 ) % self . ports_out . flow_paths . len ( ) ;
145
+ Ok ( ( ) )
146
+ }
147
+
148
+ fn passivate ( & mut self ) -> Result < Vec < ModelMessage > , SimulationError > {
149
+ self . state . phase = Phase :: LoadBalancing ;
150
+ self . state . until_next_event = INFINITY ;
151
+ Ok ( Vec :: new ( ) )
152
+ }
153
+
154
+ fn send_job ( & mut self ) -> Result < Vec < ModelMessage > , SimulationError > {
155
+ self . state . until_next_event = 0.0 ;
156
+ let job = self . state . jobs . remove ( 0 ) ;
157
+ Ok ( vec ! [ ModelMessage {
158
+ port_name: job. port_out,
159
+ content: job. content,
160
+ } ] )
161
+ }
162
+
163
+ fn release_records ( & mut self ) -> Result < Vec < ModelMessage > , SimulationError > {
164
+ self . state . phase = Phase :: LoadBalancing ;
165
+ self . state . until_next_event = 0.0 ;
166
+ Ok ( vec ! [ ModelMessage {
167
+ port_name: self . ports_out. records. clone( ) ,
168
+ content: serde_json:: to_string( & self . state. records) . unwrap( ) ,
169
+ } ] )
121
170
}
122
171
}
123
172
@@ -129,73 +178,42 @@ impl AsModel for LoadBalancer {
129
178
fn events_ext (
130
179
& mut self ,
131
180
incoming_message : & ModelMessage ,
132
- _services : & mut Services ,
181
+ services : & mut Services ,
133
182
) -> Result < Vec < ModelMessage > , SimulationError > {
134
- self . state . jobs . push ( incoming_message. content . clone ( ) ) ;
135
- self . state . event_list . push ( ScheduledEvent {
136
- time : 0.0 ,
137
- event : Event :: SendJob ,
138
- } ) ;
183
+ if incoming_message. port_name == self . ports_in . records && self . store_records {
184
+ self . request_records ( incoming_message, services) ?;
185
+ } else if incoming_message. port_name == self . ports_in . records && !self . store_records {
186
+ self . ignore_request ( incoming_message, services) ?;
187
+ } else if incoming_message. port_name == self . ports_in . job && self . store_records {
188
+ self . save_job ( incoming_message, services) ?;
189
+ } else if incoming_message. port_name == self . ports_in . job && !self . store_records {
190
+ self . pass_job ( incoming_message, services) ?;
191
+ } else {
192
+ return Err ( SimulationError :: InvalidModelState ) ;
193
+ }
139
194
Ok ( Vec :: new ( ) )
140
195
}
141
196
142
197
fn events_int (
143
198
& mut self ,
144
- services : & mut Services ,
199
+ _services : & mut Services ,
145
200
) -> Result < Vec < ModelMessage > , SimulationError > {
146
- let mut outgoing_messages: Vec < ModelMessage > = Vec :: new ( ) ;
147
- let events = self . state . event_list . clone ( ) ;
148
- self . state . event_list = self
149
- . state
150
- . event_list
151
- . iter ( )
152
- . filter ( |scheduled_event| scheduled_event. time != 0.0 )
153
- . cloned ( )
154
- . collect ( ) ;
155
- events
156
- . iter ( )
157
- . filter ( |scheduled_event| scheduled_event. time == 0.0 )
158
- . for_each ( |scheduled_event| match scheduled_event. event {
159
- Event :: Run => { }
160
- Event :: SendJob => {
161
- // Possible metrics updates
162
- if self . need_snapshot_metrics ( ) {
163
- self . snapshot . last_job = Some ( (
164
- self . ports_out . flow_paths [ self . state . next_port_out ] . clone ( ) ,
165
- self . state . jobs [ 0 ] . clone ( ) ,
166
- services. global_time ( ) ,
167
- ) ) ;
168
- }
169
- if self . need_historical_metrics ( ) {
170
- self . history . push ( self . snapshot . clone ( ) ) ;
171
- }
172
- // State changes
173
- outgoing_messages. push ( ModelMessage {
174
- port_name : self . ports_out . flow_paths [ self . state . next_port_out ] . clone ( ) ,
175
- content : self . state . jobs . remove ( 0 ) ,
176
- } ) ;
177
- self . state . next_port_out =
178
- ( self . state . next_port_out + 1 ) % self . ports_out . flow_paths . len ( ) ;
179
- }
180
- } ) ;
181
- Ok ( outgoing_messages)
201
+ if self . state . phase == Phase :: RecordsFetch {
202
+ self . release_records ( )
203
+ } else if self . state . phase == Phase :: LoadBalancing && self . state . jobs . is_empty ( ) {
204
+ self . passivate ( )
205
+ } else if self . state . phase == Phase :: LoadBalancing && !self . state . jobs . is_empty ( ) {
206
+ self . send_job ( )
207
+ } else {
208
+ Err ( SimulationError :: InvalidModelState )
209
+ }
182
210
}
183
211
184
212
fn time_advance ( & mut self , time_delta : f64 ) {
185
- self . state
186
- . event_list
187
- . iter_mut ( )
188
- . for_each ( |scheduled_event| {
189
- scheduled_event. time -= time_delta;
190
- } ) ;
213
+ self . state . until_next_event -= time_delta;
191
214
}
192
215
193
216
fn until_next_event ( & self ) -> f64 {
194
- self . state
195
- . event_list
196
- . iter ( )
197
- . fold ( INFINITY , |until_next_event, event| {
198
- f64:: min ( until_next_event, event. time )
199
- } )
217
+ self . state . until_next_event
200
218
}
201
219
}
0 commit comments