Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
a4302865
Commit
a4302865
authored
Aug 26, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Redesign distributed calculator example, fix #501
parent
efe8ce42
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
165 additions
and
137 deletions
+165
-137
examples/remoting/distributed_calculator.cpp
examples/remoting/distributed_calculator.cpp
+165
-137
No files found.
examples/remoting/distributed_calculator.cpp
View file @
a4302865
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
// Run client at the same host:
// Run client at the same host:
// - ./build/bin/distributed_math_actor -c -p 4242
// - ./build/bin/distributed_math_actor -c -p 4242
// Manual refs: 2
50-262
(ConfiguringActorSystems)
// Manual refs: 2
21-233
(ConfiguringActorSystems)
#include <array>
#include <array>
#include <vector>
#include <vector>
...
@@ -31,133 +31,164 @@ using namespace caf;
...
@@ -31,133 +31,164 @@ using namespace caf;
namespace
{
namespace
{
static
constexpr
auto
task_timeout
=
std
::
chrono
::
seconds
(
10
);
using
plus_atom
=
atom_constant
<
atom
(
"plus"
)
>
;
using
plus_atom
=
atom_constant
<
atom
(
"plus"
)
>
;
using
minus_atom
=
atom_constant
<
atom
(
"minus"
)
>
;
using
minus_atom
=
atom_constant
<
atom
(
"minus"
)
>
;
using
result_atom
=
atom_constant
<
atom
(
"result"
)
>
;
using
rebind_atom
=
atom_constant
<
atom
(
"rebind"
)
>
;
using
reconnect_atom
=
atom_constant
<
atom
(
"reconnect"
)
>
;
// our "service"
// our "service"
behavior
calculator_fun
()
{
behavior
calculator_fun
()
{
return
{
return
{
[](
plus_atom
,
int
a
,
int
b
)
->
message
{
[](
plus_atom
,
int
a
,
int
b
)
{
return
make_message
(
result_atom
::
value
,
a
+
b
)
;
return
a
+
b
;
},
},
[](
minus_atom
,
int
a
,
int
b
)
->
message
{
[](
minus_atom
,
int
a
,
int
b
)
{
return
make_message
(
result_atom
::
value
,
a
-
b
)
;
return
a
-
b
;
}
}
};
};
}
}
class
client_impl
:
public
event_based_actor
{
/* State transition of the client for connecting to the server:
public:
*
client_impl
(
actor_config
&
cfg
,
string
hostaddr
,
uint16_t
port
)
* +-------------+
:
event_based_actor
(
cfg
),
* | init |
server_
(
unsafe_actor_handle_init
),
* +-------------+
host_
(
std
::
move
(
hostaddr
)),
* |
port_
(
port
)
{
* V
set_default_handler
(
skip
);
* +-------------+
}
* | unconnected |<------------------\
* +-------------+ |
* | |
* | {connect Host Port} |
* | |
* V |
* +-------------+ {error} |
* /-------------->| connecting |------------------>|
* | +-------------+ ^
* | | |
* | | {ok, Calculator} |
* |{connect Host Port} | |
* | V |
* | +-------------+ {DOWN server} |
* \---------------| running |-------------------/
* +-------------+
*/
behavior
make_behavior
()
override
{
namespace
client
{
become
(
awaiting_task
());
become
(
keep_behavior
,
reconnecting
());
return
{};
}
private:
// a simple calculater task: operation + operands
void
request_task
(
atom_value
op
,
int
lhs
,
int
rhs
)
{
struct
task
{
request
(
server_
,
infinite
,
op
,
lhs
,
rhs
).
then
(
atom_value
op
;
[
=
](
result_atom
,
int
result
)
{
int
lhs
;
aout
(
this
)
<<
lhs
<<
(
op
==
plus_atom
::
value
?
" + "
:
" - "
)
int
rhs
;
<<
rhs
<<
" = "
<<
result
<<
endl
;
};
},
[
=
](
const
error
&
err
)
{
if
(
err
==
sec
::
request_receiver_down
)
{
aout
(
this
)
<<
"*** server down, try to reconnect ..."
<<
endl
;
// try requesting this again after successful reconnect
become
(
keep_behavior
,
reconnecting
([
=
]
{
request_task
(
op
,
lhs
,
rhs
);
}));
return
;
}
aout
(
this
)
<<
"*** request resulted in error: "
<<
system
().
render
(
err
)
<<
endl
;
}
);
// the client queues pending tasks
struct
state
{
strong_actor_ptr
current_server
;
std
::
vector
<
task
>
tasks
;
};
// prototype definition for unconnected state
behavior
unconnected
(
stateful_actor
<
state
>*
);
// prototype definition for transition to `connecting` with Host and Port
void
connecting
(
stateful_actor
<
state
>*
,
const
std
::
string
&
host
,
uint16_t
port
);
// prototype definition for transition to `running` with Calculator
behavior
running
(
stateful_actor
<
state
>*
,
actor
calculator
);
// starting point of our FSM
behavior
init
(
stateful_actor
<
state
>*
self
)
{
// transition to `unconnected` on server failure
self
->
set_down_handler
([
=
](
const
down_msg
&
dm
)
{
if
(
dm
.
source
==
self
->
state
.
current_server
)
{
aout
(
self
)
<<
"*** lost connection to server"
<<
endl
;
self
->
state
.
current_server
=
nullptr
;
self
->
become
(
unconnected
(
self
));
}
}
});
return
unconnected
(
self
);
}
behavior
awaiting_task
(
)
{
behavior
unconnected
(
stateful_actor
<
state
>*
self
)
{
return
{
return
{
[
=
](
atom_value
op
,
int
lhs
,
int
rhs
)
{
[
=
](
plus_atom
op
,
int
x
,
int
y
)
{
if
(
op
!=
plus_atom
::
value
&&
op
!=
minus_atom
::
value
)
{
self
->
state
.
tasks
.
emplace_back
(
task
{
op
,
x
,
y
});
return
;
},
}
[
=
](
minus_atom
op
,
int
x
,
int
y
)
{
request_task
(
op
,
lhs
,
rhs
);
self
->
state
.
tasks
.
emplace_back
(
task
{
op
,
x
,
y
}
);
},
},
[
=
](
rebind_atom
,
string
&
nhost
,
uint16_t
nport
)
{
[
=
](
connect_atom
,
const
std
::
string
&
host
,
uint16_t
port
)
{
aout
(
this
)
<<
"*** rebind to "
<<
nhost
<<
":"
<<
nport
<<
endl
;
connecting
(
self
,
host
,
port
);
using
std
::
swap
;
swap
(
host_
,
nhost
);
swap
(
port_
,
nport
);
become
(
keep_behavior
,
reconnecting
());
}
}
};
};
}
}
behavior
reconnecting
(
std
::
function
<
void
()
>
continuation
=
nullptr
)
{
void
connecting
(
stateful_actor
<
state
>*
self
,
using
std
::
chrono
::
seconds
;
const
std
::
string
&
host
,
uint16_t
port
)
{
auto
mm
=
system
().
middleman
().
actor_handle
();
// make sure we are not pointing to an old server
send
(
mm
,
connect_atom
::
value
,
host_
,
port_
);
self
->
state
.
current_server
=
nullptr
;
return
{
// use request().await() to suspend regular behavior until MM responded
[
=
](
ok_atom
,
node_id
&
,
strong_actor_ptr
&
new_server
,
std
::
set
<
std
::
string
>&
)
{
auto
mm
=
self
->
system
().
middleman
().
actor_handle
();
if
(
!
new_server
)
{
self
->
request
(
mm
,
infinite
,
connect_atom
::
value
,
host
,
port
).
await
(
aout
(
this
)
<<
"*** received invalid remote actor"
<<
endl
;
[
=
](
const
node_id
&
,
strong_actor_ptr
serv
,
const
std
::
set
<
std
::
string
>&
ifs
)
{
if
(
!
serv
)
{
aout
(
self
)
<<
"*** no server found at
\"
"
<<
host
<<
"
\"
:"
<<
port
<<
endl
;
return
;
return
;
}
}
aout
(
this
)
<<
"*** connection succeeded, awaiting tasks"
<<
endl
;
if
(
!
ifs
.
empty
())
{
server_
=
actor_cast
<
actor
>
(
new_server
);
aout
(
self
)
<<
"*** typed actor found at
\"
"
<<
host
<<
"
\"
:"
// return to previous behavior
<<
port
<<
", but expected an untyped actor "
<<
endl
;
if
(
continuation
)
{
return
;
continuation
();
}
}
unbecome
();
aout
(
self
)
<<
"*** successfully connected to server"
<<
endl
;
self
->
state
.
current_server
=
serv
;
auto
hdl
=
actor_cast
<
actor
>
(
serv
);
self
->
monitor
(
hdl
);
self
->
become
(
running
(
self
,
hdl
));
},
},
[
=
](
const
error
&
err
)
{
[
=
](
const
error
&
err
)
{
aout
(
this
)
<<
"*** could not connect to "
<<
host_
aout
(
self
)
<<
"*** cannot connect to
\"
"
<<
host
<<
"
\"
:"
<<
" at port "
<<
port_
<<
port
<<
" => "
<<
self
->
system
().
render
(
err
)
<<
endl
;
<<
": "
<<
system
().
render
(
err
)
self
->
become
(
unconnected
(
self
));
<<
" [try again in 3s]"
}
<<
endl
;
);
delayed_send
(
mm
,
seconds
(
3
),
connect_atom
::
value
,
host_
,
port_
);
}
},
[
=
](
rebind_atom
,
string
&
nhost
,
uint16_t
nport
)
{
// prototype definition for transition to `running` with Calculator
aout
(
this
)
<<
"*** rebind to "
<<
nhost
<<
":"
<<
nport
<<
endl
;
behavior
running
(
stateful_actor
<
state
>*
self
,
actor
calculator
)
{
using
std
::
swap
;
auto
send_task
=
[
=
](
const
task
&
x
)
{
swap
(
host_
,
nhost
);
self
->
request
(
calculator
,
task_timeout
,
x
.
op
,
x
.
lhs
,
x
.
rhs
).
then
(
swap
(
port_
,
nport
);
[
=
](
int
result
)
{
auto
send_mm
=
[
=
]
{
aout
(
self
)
<<
x
.
lhs
<<
(
x
.
op
==
plus_atom
::
value
?
" + "
:
" - "
)
unbecome
();
<<
x
.
rhs
<<
" = "
<<
result
<<
endl
;
send
(
mm
,
connect_atom
::
value
,
host_
,
port_
);
};
// await pending ok/error message first, then send new request to MM
become
(
keep_behavior
,
[
=
](
ok_atom
&
,
actor_addr
&
)
{
send_mm
();
},
},
[
=
](
const
error
&
)
{
[
=
](
const
error
&
)
{
send_mm
();
// simply try again by enqueueing the task to the mailbox again
self
->
send
(
self
,
x
.
op
,
x
.
lhs
,
x
.
rhs
);
}
}
);
);
}
};
};
for
(
auto
&
x
:
self
->
state
.
tasks
)
send_task
(
x
);
self
->
state
.
tasks
.
clear
();
return
{
[
=
](
plus_atom
op
,
int
x
,
int
y
)
{
send_task
(
task
{
op
,
x
,
y
});
},
[
=
](
minus_atom
op
,
int
x
,
int
y
)
{
send_task
(
task
{
op
,
x
,
y
});
},
[
=
](
connect_atom
,
const
std
::
string
&
host
,
uint16_t
port
)
{
connecting
(
self
,
host
,
port
);
}
}
};
}
actor
server_
;
}
// namespace client
string
host_
;
uint16_t
port_
;
};
// removes leading and trailing whitespaces
// removes leading and trailing whitespaces
string
trim
(
std
::
string
s
)
{
string
trim
(
std
::
string
s
)
{
...
@@ -173,9 +204,8 @@ string trim(std::string s) {
...
@@ -173,9 +204,8 @@ string trim(std::string s) {
optional
<
int
>
toint
(
const
string
&
str
)
{
optional
<
int
>
toint
(
const
string
&
str
)
{
char
*
end
;
char
*
end
;
auto
result
=
static_cast
<
int
>
(
strtol
(
str
.
c_str
(),
&
end
,
10
));
auto
result
=
static_cast
<
int
>
(
strtol
(
str
.
c_str
(),
&
end
,
10
));
if
(
end
==
str
.
c_str
()
+
str
.
size
())
{
if
(
end
==
str
.
c_str
()
+
str
.
size
())
return
result
;
return
result
;
}
return
none
;
return
none
;
}
}
...
@@ -188,7 +218,21 @@ optional<atom_value> plus_or_minus(const string& str) {
...
@@ -188,7 +218,21 @@ optional<atom_value> plus_or_minus(const string& str) {
return
none
;
return
none
;
}
}
void
client_repl
(
actor_system
&
system
,
string
host
,
uint16_t
port
)
{
class
config
:
public
actor_system_config
{
public:
uint16_t
port
=
0
;
std
::
string
host
=
"localhost"
;
bool
server_mode
=
false
;
config
()
{
opt_group
{
custom_options_
,
"global"
}
.
add
(
port
,
"port,p"
,
"set port"
)
.
add
(
host
,
"host,H"
,
"set host (ignored in server mode)"
)
.
add
(
server_mode
,
"server-mode,s"
,
"enable server mode"
);
}
};
void
client_repl
(
actor_system
&
system
,
const
config
&
cfg
)
{
// keeps track of requests and tries to reconnect on server failures
// keeps track of requests and tries to reconnect on server failures
auto
usage
=
[]
{
auto
usage
=
[]
{
cout
<<
"Usage:"
<<
endl
cout
<<
"Usage:"
<<
endl
...
@@ -200,7 +244,13 @@ void client_repl(actor_system& system, string host, uint16_t port) {
...
@@ -200,7 +244,13 @@ void client_repl(actor_system& system, string host, uint16_t port) {
};
};
usage
();
usage
();
bool
done
=
false
;
bool
done
=
false
;
auto
client
=
system
.
spawn
<
client_impl
>
(
std
::
move
(
host
),
port
);
auto
client
=
system
.
spawn
(
client
::
init
);
if
(
!
cfg
.
host
.
empty
()
&&
cfg
.
port
>
0
)
anon_send
(
client
,
connect_atom
::
value
,
cfg
.
host
,
cfg
.
port
);
else
cout
<<
"*** no server received via config, "
<<
"please use
\"
connect <host> <port>
\"
before using the calculator"
<<
endl
;
// defining the handler outside the loop is more efficient as it avoids
// defining the handler outside the loop is more efficient as it avoids
// re-creating the same object over and over again
// re-creating the same object over and over again
message_handler
eval
{
message_handler
eval
{
...
@@ -215,7 +265,7 @@ void client_repl(actor_system& system, string host, uint16_t port) {
...
@@ -215,7 +265,7 @@ void client_repl(actor_system& system, string host, uint16_t port) {
try
{
try
{
auto
lport
=
std
::
stoul
(
arg2
);
auto
lport
=
std
::
stoul
(
arg2
);
if
(
lport
<
std
::
numeric_limits
<
uint16_t
>::
max
())
{
if
(
lport
<
std
::
numeric_limits
<
uint16_t
>::
max
())
{
anon_send
(
client
,
rebind
_atom
::
value
,
move
(
arg1
),
anon_send
(
client
,
connect
_atom
::
value
,
move
(
arg1
),
static_cast
<
uint16_t
>
(
lport
));
static_cast
<
uint16_t
>
(
lport
));
}
}
else
{
else
{
...
@@ -247,20 +297,6 @@ void client_repl(actor_system& system, string host, uint16_t port) {
...
@@ -247,20 +297,6 @@ void client_repl(actor_system& system, string host, uint16_t port) {
}
}
}
}
class
config
:
public
actor_system_config
{
public:
uint16_t
port
=
0
;
std
::
string
host
=
"localhost"
;
bool
server_mode
=
false
;
config
()
{
opt_group
{
custom_options_
,
"global"
}
.
add
(
port
,
"port,p"
,
"set port"
)
.
add
(
host
,
"host,H"
,
"set host (ignored in server mode)"
)
.
add
(
server_mode
,
"server-mode,s"
,
"enable server mode"
);
}
};
void
run_server
(
actor_system
&
system
,
const
config
&
cfg
)
{
void
run_server
(
actor_system
&
system
,
const
config
&
cfg
)
{
auto
calc
=
system
.
spawn
(
calculator_fun
);
auto
calc
=
system
.
spawn
(
calculator_fun
);
// try to publish math actor at given port
// try to publish math actor at given port
...
@@ -279,16 +315,8 @@ void run_server(actor_system& system, const config& cfg) {
...
@@ -279,16 +315,8 @@ void run_server(actor_system& system, const config& cfg) {
anon_send_exit
(
calc
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
calc
,
exit_reason
::
user_shutdown
);
}
}
void
run_client
(
actor_system
&
system
,
const
config
&
cfg
)
{
if
(
cfg
.
port
==
0
)
{
cerr
<<
"*** no port to server specified"
<<
endl
;
return
;
}
client_repl
(
system
,
cfg
.
host
,
cfg
.
port
);
}
void
caf_main
(
actor_system
&
system
,
const
config
&
cfg
)
{
void
caf_main
(
actor_system
&
system
,
const
config
&
cfg
)
{
auto
f
=
cfg
.
server_mode
?
run_server
:
run_client
;
auto
f
=
cfg
.
server_mode
?
run_server
:
client_repl
;
f
(
system
,
cfg
);
f
(
system
,
cfg
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment