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
72e62b1a
Unverified
Commit
72e62b1a
authored
Nov 11, 2020
by
Noir
Committed by
GitHub
Nov 11, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1159
Fix communiation with remote groups
parents
cc68df1c
0af8c8cc
Changes
34
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1594 additions
and
604 deletions
+1594
-604
CHANGELOG.md
CHANGELOG.md
+1
-0
examples/remoting/group_chat.cpp
examples/remoting/group_chat.cpp
+60
-64
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+4
-1
libcaf_core/caf/abstract_group.hpp
libcaf_core/caf/abstract_group.hpp
+16
-14
libcaf_core/caf/detail/group_tunnel.hpp
libcaf_core/caf/detail/group_tunnel.hpp
+81
-0
libcaf_core/caf/detail/local_group_module.hpp
libcaf_core/caf/detail/local_group_module.hpp
+117
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+2
-1
libcaf_core/caf/group.hpp
libcaf_core/caf/group.hpp
+27
-22
libcaf_core/caf/group_manager.hpp
libcaf_core/caf/group_manager.hpp
+19
-18
libcaf_core/caf/group_module.hpp
libcaf_core/caf/group_module.hpp
+8
-11
libcaf_core/caf/local_actor.hpp
libcaf_core/caf/local_actor.hpp
+3
-0
libcaf_core/caf/message.hpp
libcaf_core/caf/message.hpp
+21
-0
libcaf_core/caf/node_id.hpp
libcaf_core/caf/node_id.hpp
+6
-1
libcaf_core/caf/scheduled_actor.hpp
libcaf_core/caf/scheduled_actor.hpp
+1
-1
libcaf_core/caf/type_id.hpp
libcaf_core/caf/type_id.hpp
+1
-0
libcaf_core/src/abstract_group.cpp
libcaf_core/src/abstract_group.cpp
+25
-10
libcaf_core/src/actor_system.cpp
libcaf_core/src/actor_system.cpp
+4
-0
libcaf_core/src/detail/group_tunnel.cpp
libcaf_core/src/detail/group_tunnel.cpp
+190
-0
libcaf_core/src/detail/local_group_module.cpp
libcaf_core/src/detail/local_group_module.cpp
+184
-0
libcaf_core/src/group.cpp
libcaf_core/src/group.cpp
+25
-15
libcaf_core/src/group_manager.cpp
libcaf_core/src/group_manager.cpp
+22
-396
libcaf_core/src/group_module.cpp
libcaf_core/src/group_module.cpp
+1
-2
libcaf_core/src/local_actor.cpp
libcaf_core/src/local_actor.cpp
+7
-3
libcaf_core/test/detail/group_tunnel.cpp
libcaf_core/test/detail/group_tunnel.cpp
+273
-0
libcaf_core/test/detail/local_group_module.cpp
libcaf_core/test/detail/local_group_module.cpp
+144
-0
libcaf_io/CMakeLists.txt
libcaf_io/CMakeLists.txt
+1
-0
libcaf_io/caf/detail/remote_group_module.hpp
libcaf_io/caf/detail/remote_group_module.hpp
+84
-0
libcaf_io/caf/io/middleman.hpp
libcaf_io/caf/io/middleman.hpp
+16
-2
libcaf_io/caf/io/middleman_actor.hpp
libcaf_io/caf/io/middleman_actor.hpp
+2
-0
libcaf_io/src/detail/remote_group_module.cpp
libcaf_io/src/detail/remote_group_module.cpp
+153
-0
libcaf_io/src/io/middleman.cpp
libcaf_io/src/io/middleman.cpp
+57
-17
libcaf_io/src/io/middleman_actor_impl.cpp
libcaf_io/src/io/middleman_actor_impl.cpp
+16
-5
libcaf_io/test/io/remote_group.cpp
libcaf_io/test/io/remote_group.cpp
+10
-8
libcaf_test/caf/test/dsl.hpp
libcaf_test/caf/test/dsl.hpp
+13
-13
No files found.
CHANGELOG.md
View file @
72e62b1a
...
@@ -39,6 +39,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
...
@@ -39,6 +39,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
failed due to undefined references to
`__atomic_fetch`
symbols. Adding a CMake
failed due to undefined references to
`__atomic_fetch`
symbols. Adding a CMake
dependency for
`caf_core`
to libatomic gets executables to compile and link as
dependency for
`caf_core`
to libatomic gets executables to compile and link as
expected (#1153).
expected (#1153).
-
Fixed a regression for remote groups introduced in 0.18.0-rc.1 (#1157).
## [0.18.0-rc.1] - 2020-09-09
## [0.18.0-rc.1] - 2020-09-09
...
...
examples/remoting/group_chat.cpp
View file @
72e62b1a
...
@@ -45,10 +45,11 @@ behavior client(event_based_actor* self, const std::string& name) {
...
@@ -45,10 +45,11 @@ behavior client(event_based_actor* self, const std::string& name) {
}
}
},
},
[
=
](
join_atom
,
const
group
&
what
)
{
[
=
](
join_atom
,
const
group
&
what
)
{
for
(
const
auto
&
g
:
self
->
joined_groups
())
{
auto
groups
=
self
->
joined_groups
();
std
::
cout
<<
"*** leave "
<<
to_string
(
g
)
<<
std
::
endl
;
for
(
auto
&&
grp
:
groups
)
{
self
->
send
(
g
,
name
+
" has left the chatroom"
);
std
::
cout
<<
"*** leave "
<<
to_string
(
grp
)
<<
std
::
endl
;
self
->
leave
(
g
);
self
->
send
(
grp
,
name
+
" has left the chatroom"
);
self
->
leave
(
grp
);
}
}
std
::
cout
<<
"*** join "
<<
to_string
(
what
)
<<
std
::
endl
;
std
::
cout
<<
"*** join "
<<
to_string
(
what
)
<<
std
::
endl
;
self
->
join
(
what
);
self
->
join
(
what
);
...
@@ -62,27 +63,31 @@ behavior client(event_based_actor* self, const std::string& name) {
...
@@ -62,27 +63,31 @@ behavior client(event_based_actor* self, const std::string& name) {
[
=
](
const
group_down_msg
&
g
)
{
[
=
](
const
group_down_msg
&
g
)
{
std
::
cout
<<
"*** chatroom offline: "
<<
to_string
(
g
.
source
)
<<
std
::
endl
;
std
::
cout
<<
"*** chatroom offline: "
<<
to_string
(
g
.
source
)
<<
std
::
endl
;
},
},
[
=
](
leave_atom
)
{
auto
groups
=
self
->
joined_groups
();
for
(
auto
&&
grp
:
groups
)
{
std
::
cout
<<
"*** leave "
<<
to_string
(
grp
)
<<
std
::
endl
;
self
->
send
(
grp
,
name
+
" has left the chatroom"
);
self
->
leave
(
grp
);
}
},
};
};
}
}
class
config
:
public
actor_system_config
{
class
config
:
public
actor_system_config
{
public:
public:
std
::
string
name
;
std
::
vector
<
std
::
string
>
group_uris
;
uint16_t
port
=
0
;
bool
server_mode
=
false
;
config
()
{
config
()
{
opt_group
{
custom_options_
,
"global"
}
opt_group
{
custom_options_
,
"global"
}
.
add
(
name
,
"name,n"
,
"set name"
)
.
add
<
std
::
string
>
(
"name,n"
,
"set name"
)
.
add
(
group_uris
,
"group,g"
,
"join group"
)
.
add
<
std
::
string
>
(
"group,g"
,
"join group"
)
.
add
(
server_mode
,
"server,s"
,
"run in server mode"
)
.
add
<
bool
>
(
"server,s"
,
"run in server mode"
)
.
add
(
port
,
"port,p"
,
"set port (ignored in client mode)"
);
.
add
<
uint16_t
>
(
"port,p"
,
"set port (ignored in client mode)"
);
}
}
};
};
void
run_server
(
actor_system
&
system
,
const
config
&
cfg
)
{
void
run_server
(
actor_system
&
sys
)
{
auto
res
=
system
.
middleman
().
publish_local_groups
(
cfg
.
port
);
auto
port
=
get_or
(
sys
.
config
(),
"port"
,
uint16_t
{
0
});
auto
res
=
sys
.
middleman
().
publish_local_groups
(
port
);
if
(
!
res
)
{
if
(
!
res
)
{
std
::
cerr
<<
"*** publishing local groups failed: "
std
::
cerr
<<
"*** publishing local groups failed: "
<<
to_string
(
res
.
error
())
<<
std
::
endl
;
<<
to_string
(
res
.
error
())
<<
std
::
endl
;
...
@@ -95,8 +100,10 @@ void run_server(actor_system& system, const config& cfg) {
...
@@ -95,8 +100,10 @@ void run_server(actor_system& system, const config& cfg) {
std
::
cout
<<
"... cya"
<<
std
::
endl
;
std
::
cout
<<
"... cya"
<<
std
::
endl
;
}
}
void
run_client
(
actor_system
&
system
,
const
config
&
cfg
)
{
void
run_client
(
actor_system
&
sys
)
{
auto
name
=
cfg
.
name
;
std
::
string
name
;
if
(
auto
config_name
=
get_if
<
std
::
string
>
(
&
sys
.
config
(),
"name"
))
name
=
*
config_name
;
while
(
name
.
empty
())
{
while
(
name
.
empty
())
{
std
::
cout
<<
"please enter your name: "
<<
std
::
flush
;
std
::
cout
<<
"please enter your name: "
<<
std
::
flush
;
if
(
!
std
::
getline
(
std
::
cin
,
name
))
{
if
(
!
std
::
getline
(
std
::
cin
,
name
))
{
...
@@ -104,61 +111,50 @@ void run_client(actor_system& system, const config& cfg) {
...
@@ -104,61 +111,50 @@ void run_client(actor_system& system, const config& cfg) {
return
;
return
;
}
}
}
}
std
::
cout
<<
"*** starting client, type '/help' for a list of commands
\n
"
;
auto
client_actor
=
sys
.
spawn
(
client
,
name
)
;
auto
client_actor
=
system
.
spawn
(
client
,
name
);
if
(
auto
locator
=
get_if
<
std
::
string
>
(
&
sys
.
config
(),
"group"
))
{
for
(
auto
&
uri
:
cfg
.
group_uris
)
{
if
(
auto
grp
=
sys
.
groups
().
get
(
*
locator
)
)
{
auto
tmp
=
system
.
groups
().
get
(
uri
);
anon_send
(
client_actor
,
join_atom_v
,
std
::
move
(
*
grp
)
);
if
(
tmp
)
}
else
{
anon_send
(
client_actor
,
join_atom_v
,
std
::
move
(
*
tmp
));
std
::
cerr
<<
R"(*** failed to parse ")"
<<
*
locator
else
<<
R"(" as group locator: )"
<<
to_string
(
grp
.
error
())
std
::
cerr
<<
R"(*** failed to parse ")"
<<
uri
<<
R"(" as group URI: )"
<<
std
::
endl
;
<<
to_string
(
tmp
.
error
())
<<
std
::
endl
;
}
}
}
std
::
cout
<<
"*** starting client, type '/help' for a list of commands
\n
"
;
std
::
istream_iterator
<
line
>
eof
;
std
::
istream_iterator
<
line
>
eof
;
std
::
vector
<
std
::
string
>
words
;
std
::
vector
<
std
::
string
>
words
;
for
(
std
::
istream_iterator
<
line
>
i
{
std
::
cin
};
i
!=
eof
;
++
i
)
{
for
(
std
::
istream_iterator
<
line
>
i
{
std
::
cin
};
i
!=
eof
;
++
i
)
{
auto
send_input
=
[
&
]
{
if
(
i
->
str
.
empty
())
{
if
(
!
i
->
str
.
empty
())
// Ignore empty lines.
anon_send
(
client_actor
,
broadcast_atom_v
,
i
->
str
);
}
else
if
(
i
->
str
[
0
]
==
'/'
)
{
};
words
.
clear
();
words
.
clear
();
split
(
words
,
i
->
str
,
is_any_of
(
" "
));
split
(
words
,
i
->
str
,
is_any_of
(
" "
));
if
(
words
.
size
()
==
3
&&
words
[
0
]
==
"/join"
)
{
message_handler
f
{
if
(
auto
grp
=
sys
.
groups
().
get
(
words
[
1
],
words
[
2
]))
[
&
](
const
std
::
string
&
cmd
,
const
std
::
string
&
mod
,
anon_send
(
client_actor
,
join_atom_v
,
*
grp
);
const
std
::
string
&
id
)
{
else
if
(
cmd
==
"/join"
)
{
std
::
cerr
<<
"*** failed to join group: "
<<
to_string
(
grp
.
error
())
auto
grp
=
system
.
groups
().
get
(
mod
,
id
);
<<
std
::
endl
;
if
(
grp
)
}
else
if
(
words
.
size
()
==
1
&&
words
[
0
]
==
"/quit"
)
{
anon_send
(
client_actor
,
join_atom_v
,
*
grp
);
std
::
cin
.
setstate
(
std
::
ios_base
::
eofbit
);
}
else
{
}
else
{
send_input
();
std
::
cout
<<
"*** available commands:
\n
"
}
" /join <module> <group> join a new chat channel
\n
"
},
" /quit quit the program
\n
"
[
&
](
const
std
::
string
&
cmd
)
{
" /help print this text
\n
"
;
if
(
cmd
==
"/quit"
)
{
}
std
::
cin
.
setstate
(
std
::
ios_base
::
eofbit
);
}
else
{
}
else
if
(
cmd
[
0
]
==
'/'
)
{
anon_send
(
client_actor
,
broadcast_atom_v
,
i
->
str
);
std
::
cout
<<
"*** available commands:
\n
"
}
" /join <module> <group> join a new chat channel
\n
"
" /quit quit the program
\n
"
" /help print this text
\n
"
;
}
else
{
send_input
();
}
},
};
auto
msg
=
message_builder
(
words
.
begin
(),
words
.
end
()).
move_to_message
();
auto
res
=
f
(
msg
);
if
(
!
res
)
send_input
();
}
}
// force actor to quit
anon_send
(
client_actor
,
leave_atom_v
);
anon_send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
}
}
void
caf_main
(
actor_system
&
sys
tem
,
const
config
&
cfg
)
{
void
caf_main
(
actor_system
&
sys
,
const
config
&
cfg
)
{
auto
f
=
cfg
.
server_mode
?
run_server
:
run_client
;
auto
f
=
get_or
(
cfg
,
"server"
,
false
)
?
run_server
:
run_client
;
f
(
sys
tem
,
cfg
);
f
(
sys
);
}
}
CAF_MAIN
(
id_block
::
group_chat
,
io
::
middleman
)
CAF_MAIN
(
id_block
::
group_chat
,
io
::
middleman
)
libcaf_core/CMakeLists.txt
View file @
72e62b1a
...
@@ -86,7 +86,9 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
...
@@ -86,7 +86,9 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/get_process_id.cpp
src/detail/get_process_id.cpp
src/detail/get_root_uuid.cpp
src/detail/get_root_uuid.cpp
src/detail/glob_match.cpp
src/detail/glob_match.cpp
src/detail/group_tunnel.cpp
src/detail/invoke_result_visitor.cpp
src/detail/invoke_result_visitor.cpp
src/detail/local_group_module.cpp
src/detail/message_builder_element.cpp
src/detail/message_builder_element.cpp
src/detail/message_data.cpp
src/detail/message_data.cpp
src/detail/meta_object.cpp
src/detail/meta_object.cpp
...
@@ -265,8 +267,10 @@ caf_add_test_suites(caf-core-test
...
@@ -265,8 +267,10 @@ caf_add_test_suites(caf-core-test
detail.bounds_checker
detail.bounds_checker
detail.config_consumer
detail.config_consumer
detail.encode_base64
detail.encode_base64
detail.group_tunnel
detail.ieee_754
detail.ieee_754
detail.limited_vector
detail.limited_vector
detail.local_group_module
detail.meta_object
detail.meta_object
detail.parse
detail.parse
detail.parser.read_bool
detail.parser.read_bool
...
@@ -309,7 +313,6 @@ caf_add_test_suites(caf-core-test
...
@@ -309,7 +313,6 @@ caf_add_test_suites(caf-core-test
ipv6_endpoint
ipv6_endpoint
ipv6_subnet
ipv6_subnet
load_inspector
load_inspector
local_group
logger
logger
mailbox_element
mailbox_element
message
message
...
...
libcaf_core/caf/abstract_group.hpp
View file @
72e62b1a
...
@@ -60,13 +60,16 @@ public:
...
@@ -60,13 +60,16 @@ public:
// -- observers --------------------------------------------------------------
// -- observers --------------------------------------------------------------
/// Returns the hosting system.
/// Returns the hosting system.
actor_system
&
system
()
const
{
actor_system
&
system
()
const
noexcept
;
return
system_
;
}
/// Returns the parent module.
/// Returns the parent module.
group_module
&
module
()
const
{
group_module
&
module
()
const
noexcept
{
return
parent_
;
return
*
parent_
;
}
/// Returns the origin node of the group if applicable.
node_id
origin
()
const
noexcept
{
return
origin_
;
}
}
/// Returns a string representation of the group identifier, e.g.,
/// Returns a string representation of the group identifier, e.g.,
...
@@ -75,19 +78,18 @@ public:
...
@@ -75,19 +78,18 @@ public:
return
identifier_
;
return
identifier_
;
}
}
/// @private
/// Returns a human-readable string representation of the group ID.
const
actor
&
dispatcher
()
{
virtual
std
::
string
stringify
()
const
;
return
dispatcher_
;
}
/// Returns the intermediary actor for the group if applicable.
virtual
actor
intermediary
()
const
noexcept
;
protected:
protected:
abstract_group
(
group_module
&
mod
,
std
::
string
id
,
node_id
nid
);
abstract_group
(
group_module
_ptr
mod
,
std
::
string
id
,
node_id
nid
);
actor_system
&
system_
;
group_module_ptr
parent_
;
group_module
&
parent_
;
std
::
string
identifier_
;
node_id
origin_
;
node_id
origin_
;
actor
dispatch
er_
;
std
::
string
identifi
er_
;
};
};
/// A smart pointer type that manages instances of {@link group}.
/// A smart pointer type that manages instances of {@link group}.
...
...
libcaf_core/
test/local_group.c
pp
→
libcaf_core/
caf/detail/group_tunnel.h
pp
View file @
72e62b1a
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* \____/_/ \_|_| *
* *
* *
* Copyright 2011-20
18
Dominik Charousset *
* Copyright 2011-20
20
Dominik Charousset *
* *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* (at your option) under the terms and conditions of the Boost Software *
...
@@ -16,71 +16,66 @@
...
@@ -16,71 +16,66 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#
define CAF_SUITE local_group
#
pragma once
#include "caf/all.hpp"
#include "caf/abstract_group.hpp"
#include "caf/actor.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/local_group_module.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/fwd.hpp"
#include "caf/stateful_actor.hpp"
#include
"core-test.hpp"
#include
<tuple>
#include <array>
namespace
caf
::
detail
{
#include <chrono>
#include <algorithm>
using
namespace
caf
;
/// Represents a group that runs on a remote CAF node.
class
CAF_CORE_EXPORT
group_tunnel
:
public
local_group_module
::
impl
{
public:
using
super
=
local_group_module
::
impl
;
namespace
{
using
cached_message
=
std
::
tuple
<
strong_actor_ptr
,
message_id
,
message
>
;
using
testee_if
using
cached_message_list
=
std
::
vector
<
cached_message
>
;
=
typed_actor
<
replies_to
<
get_atom
>::
with
<
int
>
,
reacts_to
<
put_atom
,
int
>>
;
struct
testee_state
{
// Creates a connected tunnel.
int
x
=
0
;
group_tunnel
(
group_module_ptr
mod
,
std
::
string
id
,
};
actor
upstream_intermediary
);
// Creates an unconnected tunnel that caches incoming messages until it
// becomes connected to the upstream intermediary.
group_tunnel
(
group_module_ptr
mod
,
std
::
string
id
,
node_id
origin
);
~
group_tunnel
()
override
;
bool
subscribe
(
strong_actor_ptr
who
)
override
;
void
unsubscribe
(
const
actor_control_block
*
who
)
override
;
// Locally enqueued message, forwarded via worker_.
void
enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
)
override
;
void
stop
()
override
;
std
::
string
stringify
()
const
override
;
// Messages received from the upstream group, forwarded to local subscribers.
void
upstream_enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
);
bool
connect
(
actor
upstream_intermediary
);
bool
connected
()
const
noexcept
;
actor
worker
()
const
noexcept
;
behavior
testee_impl
(
stateful_actor
<
testee_state
>*
self
)
{
private:
auto
subscriptions
=
self
->
joined_groups
();
actor
worker_
;
return
{
cached_message_list
cached_messages_
;
[
=
](
put_atom
,
int
x
)
{
self
->
state
.
x
=
x
;
},
[
=
](
get_atom
)
{
return
self
->
state
.
x
;
}
};
}
struct
fixture
{
actor_system_config
config
;
actor_system
system
{
config
};
scoped_actor
self
{
system
};
};
};
}
// namespace
using
group_tunnel_ptr
=
intrusive_ptr
<
group_tunnel
>
;
CAF_TEST_FIXTURE_SCOPE
(
group_tests
,
fixture
)
CAF_TEST
(
class_based_joined_at_spawn
)
{
auto
grp
=
system
.
groups
().
get_local
(
"test"
);
// initialize all testee actors, spawning them in the group
std
::
array
<
actor
,
10
>
xs
;
for
(
auto
&
x
:
xs
)
x
=
system
.
spawn_in_group
(
grp
,
testee_impl
);
// get a function view for all testees
std
::
array
<
function_view
<
testee_if
>
,
10
>
fs
;
std
::
transform
(
xs
.
begin
(),
xs
.
end
(),
fs
.
begin
(),
[](
const
actor
&
x
)
{
return
make_function_view
(
actor_cast
<
testee_if
>
(
x
));
});
// make sure all actors start at 0
for
(
auto
&
f
:
fs
)
CAF_CHECK_EQUAL
(
f
(
get_atom_v
),
0
);
// send a put to all actors via the group and make sure they change state
self
->
send
(
grp
,
put_atom_v
,
42
);
for
(
auto
&
f
:
fs
)
CAF_CHECK_EQUAL
(
f
(
get_atom_v
),
42
);
// shutdown all actors
for
(
auto
&
x
:
xs
)
self
->
send_exit
(
x
,
exit_reason
::
user_shutdown
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
}
// namespace caf::detail
libcaf_core/caf/detail/local_group_module.hpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <functional>
#include <mutex>
#include <set>
#include <unordered_map>
#include "caf/abstract_group.hpp"
#include "caf/group_module.hpp"
namespace
caf
::
detail
{
/// Simple group implementation that allows arbitrary strings as group names.
/// However, the group names must use a string representation of the local node
/// ID as prefix. Each group instance spins up an intermediary actor to enable
/// remote access to the group. The default module is used internally by the
/// "local" as well as the "remote" module.
class
CAF_CORE_EXPORT
local_group_module
:
public
group_module
{
public:
using
super
=
group_module
;
struct
intermediary_actor_state
{
static
inline
const
char
*
name
=
"caf.detail.group-intermediary"
;
intermediary_actor_state
(
event_based_actor
*
self
,
abstract_group_ptr
gptr
);
behavior
make_behavior
();
event_based_actor
*
self
;
abstract_group_ptr
gptr
;
};
/// A group intermediary enables remote actors to join and leave groups on
/// this endpoint as well as sending message to it.
using
intermediary_actor
=
stateful_actor
<
intermediary_actor_state
>
;
/// Implementation of the group interface for instances of this module.
class
CAF_CORE_EXPORT
impl
:
public
abstract_group
{
public:
friend
local_group_module
;
using
super
=
abstract_group
;
using
subscriber_set
=
std
::
set
<
strong_actor_ptr
,
std
::
less
<>>
;
impl
(
group_module_ptr
mod
,
std
::
string
id
,
node_id
origin
);
impl
(
group_module_ptr
mod
,
std
::
string
id
);
~
impl
()
override
;
void
enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
)
override
;
bool
subscribe
(
strong_actor_ptr
who
)
override
;
void
unsubscribe
(
const
actor_control_block
*
who
)
override
;
actor
intermediary
()
const
noexcept
override
;
void
stop
()
override
;
protected:
template
<
class
F
>
auto
critical_section
(
F
&&
fun
)
const
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
return
fun
();
}
/// @pre `mtx_` is locked
std
::
pair
<
bool
,
size_t
>
subscribe_impl
(
strong_actor_ptr
who
);
/// @pre `mtx_` is locked
std
::
pair
<
bool
,
size_t
>
unsubscribe_impl
(
const
actor_control_block
*
who
);
mutable
std
::
mutex
mtx_
;
actor
intermediary_
;
bool
stopped_
=
false
;
subscriber_set
subscribers_
;
};
using
instances_map
=
std
::
unordered_map
<
std
::
string
,
intrusive_ptr
<
impl
>>
;
explicit
local_group_module
(
actor_system
&
sys
);
~
local_group_module
()
override
;
expected
<
group
>
get
(
const
std
::
string
&
group_name
)
override
;
void
stop
()
override
;
private:
std
::
mutex
mtx_
;
bool
stopped_
=
false
;
instances_map
instances_
;
};
}
// namespace caf::detail
libcaf_core/caf/fwd.hpp
View file @
72e62b1a
...
@@ -381,8 +381,9 @@ using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
...
@@ -381,8 +381,9 @@ using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
// -- intrusive pointer aliases ------------------------------------------------
// -- intrusive pointer aliases ------------------------------------------------
using
strong_actor_ptr
=
intrusive_ptr
<
actor_control_block
>
;
using
group_module_ptr
=
intrusive_ptr
<
group_module
>
;
using
stream_manager_ptr
=
intrusive_ptr
<
stream_manager
>
;
using
stream_manager_ptr
=
intrusive_ptr
<
stream_manager
>
;
using
strong_actor_ptr
=
intrusive_ptr
<
actor_control_block
>
;
// -- unique pointer aliases ---------------------------------------------------
// -- unique pointer aliases ---------------------------------------------------
...
...
libcaf_core/caf/group.hpp
View file @
72e62b1a
...
@@ -42,7 +42,8 @@ struct invalid_group_t {
...
@@ -42,7 +42,8 @@ struct invalid_group_t {
constexpr
invalid_group_t
invalid_group
=
invalid_group_t
{};
constexpr
invalid_group_t
invalid_group
=
invalid_group_t
{};
class
CAF_CORE_EXPORT
group
:
detail
::
comparable
<
group
>
,
class
CAF_CORE_EXPORT
group
:
detail
::
comparable
<
group
>
,
detail
::
comparable
<
group
,
invalid_group_t
>
{
detail
::
comparable
<
group
,
invalid_group_t
>
,
detail
::
comparable
<
group
,
std
::
nullptr_t
>
{
public:
public:
using
signatures
=
none_t
;
using
signatures
=
none_t
;
...
@@ -52,17 +53,15 @@ public:
...
@@ -52,17 +53,15 @@ public:
group
(
const
group
&
)
=
default
;
group
(
const
group
&
)
=
default
;
group
(
const
invalid_group_t
&
);
group
(
invalid_group_t
);
explicit
group
(
intrusive_ptr
<
abstract_group
>
gptr
);
group
&
operator
=
(
group
&&
)
=
default
;
group
&
operator
=
(
group
&&
)
=
default
;
group
&
operator
=
(
const
group
&
)
=
default
;
group
&
operator
=
(
const
group
&
)
=
default
;
group
&
operator
=
(
const
invalid_group_t
&
);
group
&
operator
=
(
invalid_group_t
);
group
(
abstract_group
*
);
group
(
intrusive_ptr
<
abstract_group
>
gptr
);
explicit
operator
bool
()
const
noexcept
{
explicit
operator
bool
()
const
noexcept
{
return
static_cast
<
bool
>
(
ptr_
);
return
static_cast
<
bool
>
(
ptr_
);
...
@@ -76,7 +75,11 @@ public:
...
@@ -76,7 +75,11 @@ public:
intptr_t
compare
(
const
group
&
other
)
const
noexcept
;
intptr_t
compare
(
const
group
&
other
)
const
noexcept
;
intptr_t
compare
(
const
invalid_group_t
&
)
const
noexcept
{
intptr_t
compare
(
invalid_group_t
)
const
noexcept
{
return
ptr_
?
1
:
0
;
}
intptr_t
compare
(
std
::
nullptr_t
)
const
noexcept
{
return
ptr_
?
1
:
0
;
return
ptr_
?
1
:
0
;
}
}
...
@@ -116,22 +119,20 @@ public:
...
@@ -116,22 +119,20 @@ public:
template
<
class
Inspector
>
template
<
class
Inspector
>
friend
bool
inspect
(
Inspector
&
f
,
group
&
x
)
{
friend
bool
inspect
(
Inspector
&
f
,
group
&
x
)
{
std
::
string
module_name
;
node_id
origin
;
std
::
string
group_name
;
std
::
string
mod
;
actor
dispatcher
;
std
::
string
id
;
if
constexpr
(
!
Inspector
::
is_loading
)
{
if
constexpr
(
!
Inspector
::
is_loading
)
{
if
(
x
)
{
if
(
x
)
{
module_name
=
x
.
get
()
->
module
().
name
();
origin
=
x
.
get
()
->
origin
();
group_name
=
x
.
get
()
->
identifier
();
mod
=
x
.
get
()
->
module
().
name
();
dispatcher
=
x
.
get
()
->
dispatch
er
();
id
=
x
.
get
()
->
identifi
er
();
}
}
}
}
auto
load_cb
=
[
&
]
{
auto
load_cb
=
[
&
]
{
if
constexpr
(
detail
::
has_context
<
Inspector
>::
value
)
{
if
constexpr
(
detail
::
has_context
<
Inspector
>::
value
)
{
auto
ctx
=
f
.
context
();
if
(
auto
ctx
=
f
.
context
())
{
if
(
ctx
!=
nullptr
)
{
if
(
auto
grp
=
load_impl
(
ctx
->
system
(),
origin
,
mod
,
id
))
{
if
(
auto
grp
=
ctx
->
system
().
groups
().
get
(
module_name
,
group_name
,
dispatcher
))
{
x
=
std
::
move
(
*
grp
);
x
=
std
::
move
(
*
grp
);
return
true
;
return
true
;
}
else
{
}
else
{
...
@@ -144,15 +145,19 @@ public:
...
@@ -144,15 +145,19 @@ public:
return
false
;
return
false
;
};
};
return
f
.
object
(
x
)
return
f
.
object
(
x
)
.
on_load
(
load_cb
)
//
.
on_load
(
load_cb
)
//
.
fields
(
f
.
field
(
"
module_name"
,
module_name
),
.
fields
(
f
.
field
(
"
origin"
,
origin
),
//
f
.
field
(
"
group_name"
,
group_name
),
f
.
field
(
"
module"
,
mod
),
//
f
.
field
(
"
dispatcher"
,
dispatcher
));
f
.
field
(
"
identifier"
,
id
));
}
}
/// @endcond
/// @endcond
private:
private:
static
expected
<
group
>
load_impl
(
actor_system
&
sys
,
const
node_id
&
origin
,
const
std
::
string
&
mod
,
const
std
::
string
&
id
);
abstract_group
*
release
()
noexcept
{
abstract_group
*
release
()
noexcept
{
return
ptr_
.
release
();
return
ptr_
.
release
();
}
}
...
...
libcaf_core/caf/group_manager.hpp
View file @
72e62b1a
...
@@ -18,18 +18,15 @@
...
@@ -18,18 +18,15 @@
#pragma once
#pragma once
#include <map>
#include <atomic>
#include <mutex>
#include <functional>
#include <thread>
#include <unordered_map>
#include <unordered_map>
#include "caf/abstract_group.hpp"
#include "caf/abstract_group.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/expected.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/group_module.hpp"
#include "caf/group_module.hpp"
#include "caf/optional.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -38,11 +35,17 @@ public:
...
@@ -38,11 +35,17 @@ public:
// -- friends ----------------------------------------------------------------
// -- friends ----------------------------------------------------------------
friend
class
actor_system
;
friend
class
actor_system
;
friend
class
group
;
friend
class
io
::
middleman
;
// -- member types -----------------------------------------------------------
// -- member types -----------------------------------------------------------
using
modules_map
using
modules_map
=
std
::
unordered_map
<
std
::
string
,
group_module_ptr
>
;
=
std
::
unordered_map
<
std
::
string
,
std
::
unique_ptr
<
group_module
>>
;
using
get_remote_fun
=
std
::
function
<
expected
<
group
>
(
const
node_id
&
origin
,
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
)
>
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
...
@@ -57,34 +60,31 @@ public:
...
@@ -57,34 +60,31 @@ public:
/// Get a handle to the group associated with given URI scheme.
/// Get a handle to the group associated with given URI scheme.
/// @threadsafe
/// @threadsafe
/// @experimental
/// @experimental
expected
<
group
>
get
(
std
::
string
group_uri
)
const
;
expected
<
group
>
get
(
std
::
string
group_uri
);
/// Get a handle to the group associated with
/// Get a handle to the group associated with
/// `identifier` from the module `mod_name`.
/// `identifier` from the module `mod_name`.
/// @threadsafe
/// @threadsafe
expected
<
group
>
get
(
const
std
::
string
&
module_name
,
expected
<
group
>
get
(
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
)
const
;
const
std
::
string
&
group_identifier
);
/// Get a pointer to the group associated with
/// Get a pointer to the group associated with
/// `identifier` from the module `local`.
/// `identifier` from the module `local`.
/// @threadsafe
/// @threadsafe
group
get_local
(
const
std
::
string
&
group_identifier
)
const
;
group
get_local
(
const
std
::
string
&
group_identifier
);
/// Returns an anonymous group.
/// Returns an anonymous group.
/// Each calls to this member function returns a new instance
/// Each calls to this member function returns a new instance
/// of an anonymous group. Anonymous groups can be used whenever
/// of an anonymous group. Anonymous groups can be used whenever
/// a set of actors wants to communicate using an exclusive channel.
/// a set of actors wants to communicate using an exclusive channel.
group
anonymous
()
const
;
group
anonymous
();
/// Returns the module named `name` if it exists, otherwise `none`.
/// Returns the module named `name` if it exists, otherwise `none`.
optional
<
group_module
&>
get_module
(
const
std
::
string
&
x
)
const
;
group_module_ptr
get_module
(
const
std
::
string
&
x
)
const
;
/// @private
expected
<
group
>
get
(
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
,
const
caf
::
actor
&
dispatcher
)
const
;
private:
private:
get_remote_fun
get_remote
;
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
explicit
group_manager
(
actor_system
&
sys
);
explicit
group_manager
(
actor_system
&
sys
);
...
@@ -100,7 +100,8 @@ private:
...
@@ -100,7 +100,8 @@ private:
// -- data members -----------------------------------------------------------
// -- data members -----------------------------------------------------------
modules_map
mmap_
;
modules_map
mmap_
;
actor_system
&
system_
;
actor_system
*
system_
;
std
::
atomic
<
size_t
>
ad_hoc_id_
;
};
};
}
// namespace caf
}
// namespace caf
libcaf_core/caf/group_module.hpp
View file @
72e62b1a
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
namespace
caf
{
namespace
caf
{
/// Interface for user-defined multicast implementations.
/// Interface for user-defined multicast implementations.
class
CAF_CORE_EXPORT
group_module
{
class
CAF_CORE_EXPORT
group_module
:
public
ref_counted
{
public:
public:
// -- constructors, destructors, and assignment operators --------------------
// -- constructors, destructors, and assignment operators --------------------
...
@@ -41,7 +41,7 @@ public:
...
@@ -41,7 +41,7 @@ public:
group_module
&
operator
=
(
const
group_module
&
)
=
delete
;
group_module
&
operator
=
(
const
group_module
&
)
=
delete
;
virtual
~
group_module
()
;
~
group_module
()
override
;
// -- pure virtual member functions ------------------------------------------
// -- pure virtual member functions ------------------------------------------
...
@@ -52,26 +52,23 @@ public:
...
@@ -52,26 +52,23 @@ public:
/// @threadsafe
/// @threadsafe
virtual
expected
<
group
>
get
(
const
std
::
string
&
group_name
)
=
0
;
virtual
expected
<
group
>
get
(
const
std
::
string
&
group_name
)
=
0
;
/// Returns a pointer to the group associated with the name `group_name`.
/// @threadsafe
virtual
expected
<
group
>
get
(
const
std
::
string
&
group_name
,
const
caf
::
actor
&
dispatcher
)
=
0
;
// -- observers --------------------------------------------------------------
// -- observers --------------------------------------------------------------
/// Returns the hosting actor system.
/// Returns the hosting actor system.
actor_system
&
system
()
const
{
actor_system
&
system
()
const
noexcept
{
return
system_
;
return
*
system_
;
}
}
/// Returns the name of this module implementation.
/// Returns the name of this module implementation.
const
std
::
string
&
name
()
const
{
const
std
::
string
&
name
()
const
noexcept
{
return
name_
;
return
name_
;
}
}
private:
private:
actor_system
&
system_
;
actor_system
*
system_
;
std
::
string
name_
;
std
::
string
name_
;
};
};
using
group_module_ptr
=
intrusive_ptr
<
group_module
>
;
}
// namespace caf
}
// namespace caf
libcaf_core/caf/local_actor.hpp
View file @
72e62b1a
...
@@ -335,6 +335,9 @@ public:
...
@@ -335,6 +335,9 @@ public:
/// Removes a monitor from `whom`.
/// Removes a monitor from `whom`.
void
demonitor
(
const
actor_addr
&
whom
);
void
demonitor
(
const
actor_addr
&
whom
);
/// Removes a monitor from `whom`.
void
demonitor
(
const
strong_actor_ptr
&
whom
);
/// Removes a monitor from `node`.
/// Removes a monitor from `node`.
void
demonitor
(
const
node_id
&
node
);
void
demonitor
(
const
node_id
&
node
);
...
...
libcaf_core/caf/message.hpp
View file @
72e62b1a
...
@@ -114,6 +114,14 @@ public:
...
@@ -114,6 +114,14 @@ public:
return
!
data_
;
return
!
data_
;
}
}
/// Checks whether this messages contains the types `Ts...` with values
/// `values...`. Users may pass `std::ignore` as a wildcard for individual
/// elements. Elements are compared using `operator==`.
template
<
class
...
Ts
>
bool
matches
(
const
Ts
&
...
values
)
const
{
return
matches_impl
(
std
::
index_sequence_for
<
Ts
...
>
{},
values
...);
}
// -- serialization ----------------------------------------------------------
// -- serialization ----------------------------------------------------------
bool
save
(
serializer
&
sink
)
const
;
bool
save
(
serializer
&
sink
)
const
;
...
@@ -174,6 +182,19 @@ public:
...
@@ -174,6 +182,19 @@ public:
}
}
private:
private:
template
<
size_t
Pos
,
class
T
>
bool
matches_at
(
const
T
&
value
)
const
{
if
constexpr
(
std
::
is_same
<
T
,
decltype
(
std
::
ignore
)
>::
value
)
return
true
;
else
return
match_element
<
T
>
(
Pos
)
&&
get_as
<
T
>
(
Pos
)
==
value
;
}
template
<
size_t
...
Is
,
class
...
Ts
>
bool
matches_impl
(
std
::
index_sequence
<
Is
...
>
,
const
Ts
&
...
values
)
const
{
return
(
matches_at
<
Is
>
(
values
)
&&
...);
}
data_ptr
data_
;
data_ptr
data_
;
};
};
...
...
libcaf_core/caf/node_id.hpp
View file @
72e62b1a
...
@@ -150,10 +150,15 @@ public:
...
@@ -150,10 +150,15 @@ public:
// -- properties -------------------------------------------------------------
// -- properties -------------------------------------------------------------
/// Queries whether this node is not default-constructed.
/// Queries whether this node is not default-constructed.
explicit
operator
bool
()
const
{
explicit
operator
bool
()
const
noexcept
{
return
static_cast
<
bool
>
(
data_
);
return
static_cast
<
bool
>
(
data_
);
}
}
/// Queries whether this node is default-constructed.
bool
operator
!
()
const
noexcept
{
return
!
data_
;
}
/// Compares this instance to `other`.
/// Compares this instance to `other`.
/// @returns -1 if `*this < other`, 0 if `*this == other`, and 1 otherwise.
/// @returns -1 if `*this < other`, 0 if `*this == other`, and 1 otherwise.
int
compare
(
const
node_id
&
other
)
const
noexcept
;
int
compare
(
const
node_id
&
other
)
const
noexcept
;
...
...
libcaf_core/caf/scheduled_actor.hpp
View file @
72e62b1a
...
@@ -309,7 +309,7 @@ public:
...
@@ -309,7 +309,7 @@ public:
/// Sets a custom handler for unexpected messages.
/// Sets a custom handler for unexpected messages.
template
<
class
F
>
template
<
class
F
>
typename
std
::
enable_if
<
std
::
is_convertible
<
typename
std
::
enable_if
<
std
::
is_convertible
<
F
,
std
::
function
<
result
<
message
>
(
message
&
)
>>::
value
>::
type
F
,
std
::
function
<
skippable_result
(
message
&
)
>>::
value
>::
type
set_default_handler
(
F
fun
)
{
set_default_handler
(
F
fun
)
{
default_handler_
=
[
=
](
scheduled_actor
*
,
message
&
xs
)
{
return
fun
(
xs
);
};
default_handler_
=
[
=
](
scheduled_actor
*
,
message
&
xs
)
{
return
fun
(
xs
);
};
}
}
...
...
libcaf_core/caf/type_id.hpp
View file @
72e62b1a
...
@@ -349,6 +349,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
...
@@ -349,6 +349,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_ATOM
(
core_module
,
caf
,
flush_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
flush_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
forward_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
forward_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
get_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
get_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
group_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
idle_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
idle_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
join_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
join_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
leave_atom
)
CAF_ADD_ATOM
(
core_module
,
caf
,
leave_atom
)
...
...
libcaf_core/src/abstract_group.cpp
View file @
72e62b1a
...
@@ -18,21 +18,21 @@
...
@@ -18,21 +18,21 @@
#include "caf/abstract_group.hpp"
#include "caf/abstract_group.hpp"
#include "caf/group.hpp"
#include "caf/message.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_cast.hpp"
#include "caf/group_module.hpp"
#include "caf/group_manager.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/group.hpp"
#include "caf/group_manager.hpp"
#include "caf/group_module.hpp"
#include "caf/message.hpp"
namespace
caf
{
namespace
caf
{
abstract_group
::
abstract_group
(
group_module
&
mod
,
std
::
string
id
,
node_id
nid
)
abstract_group
::
abstract_group
(
group_module
_ptr
mod
,
std
::
string
id
,
:
abstract_channel
(
abstract_channel
::
is_abstract_group_flag
),
node_id
nid
)
system_
(
mod
.
system
()
),
:
abstract_channel
(
abstract_channel
::
is_abstract_group_flag
),
parent_
(
mod
),
parent_
(
std
::
move
(
mod
)
),
identifier_
(
std
::
move
(
id
)),
origin_
(
std
::
move
(
n
id
)),
origin_
(
std
::
move
(
n
id
))
{
identifier_
(
std
::
move
(
id
))
{
// nop
// nop
}
}
...
@@ -40,4 +40,19 @@ abstract_group::~abstract_group() {
...
@@ -40,4 +40,19 @@ abstract_group::~abstract_group() {
// nop
// nop
}
}
actor_system
&
abstract_group
::
system
()
const
noexcept
{
return
module
().
system
();
}
std
::
string
abstract_group
::
stringify
()
const
{
auto
result
=
module
().
name
();
result
+=
':'
;
result
+=
identifier
();
return
result
;
}
actor
abstract_group
::
intermediary
()
const
noexcept
{
return
{};
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/actor_system.cpp
View file @
72e62b1a
...
@@ -135,6 +135,10 @@ behavior config_serv_impl(stateful_actor<kvstate>* self) {
...
@@ -135,6 +135,10 @@ behavior config_serv_impl(stateful_actor<kvstate>* self) {
[
=
](
registry_lookup_atom
,
const
std
::
string
&
name
)
{
[
=
](
registry_lookup_atom
,
const
std
::
string
&
name
)
{
return
self
->
home_system
().
registry
().
get
(
name
);
return
self
->
home_system
().
registry
().
get
(
name
);
},
},
// get the intermediary of a local group
[
=
](
get_atom
,
group_atom
,
const
std
::
string
&
id
)
{
return
self
->
home_system
().
groups
().
get_local
(
id
).
get
()
->
intermediary
();
},
};
};
}
}
...
...
libcaf_core/src/detail/group_tunnel.cpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/group_tunnel.hpp"
namespace
caf
::
detail
{
namespace
{
struct
group_worker_actor_state
{
static
inline
const
char
*
name
=
"caf.detail.group-tunnel"
;
group_worker_actor_state
(
event_based_actor
*
self
,
group_tunnel_ptr
gptr
,
actor
intermediary
)
:
self
(
self
),
gptr
(
std
::
move
(
gptr
)),
intermediary
(
std
::
move
(
intermediary
))
{
// nop
}
behavior
make_behavior
()
{
self
->
set_down_handler
([
this
](
const
down_msg
&
dm
)
{
if
(
dm
.
source
==
intermediary
)
{
gptr
->
stop
();
}
});
self
->
set_default_handler
([
this
](
message
&
msg
)
->
skippable_result
{
gptr
->
upstream_enqueue
(
std
::
move
(
self
->
current_sender
()),
self
->
take_current_message_id
(),
std
::
move
(
msg
),
self
->
context
());
return
message
{};
});
self
->
monitor
(
intermediary
);
return
{
[
this
](
sys_atom
,
join_atom
)
{
self
->
send
(
intermediary
,
join_atom_v
,
self
->
ctrl
());
},
[
this
](
sys_atom
,
leave_atom
)
{
self
->
send
(
intermediary
,
leave_atom_v
,
self
->
ctrl
());
},
[
this
](
sys_atom
,
forward_atom
,
message
&
msg
)
{
self
->
delegate
(
intermediary
,
forward_atom_v
,
std
::
move
(
msg
));
},
};
}
event_based_actor
*
self
;
group_tunnel_ptr
gptr
;
actor
intermediary
;
};
// A group tunnel enables remote actors to join and leave groups on this
// endpoint as well as sending message to it.
using
group_worker_actor
=
stateful_actor
<
group_worker_actor_state
>
;
}
// namespace
group_tunnel
::
group_tunnel
(
group_module_ptr
mod
,
std
::
string
id
,
actor
upstream_intermediary
)
:
super
(
std
::
move
(
mod
),
std
::
move
(
id
),
upstream_intermediary
.
node
())
{
intermediary_
=
std
::
move
(
upstream_intermediary
);
worker_
=
system
().
spawn
<
group_worker_actor
,
hidden
>
(
this
,
intermediary_
);
}
group_tunnel
::
group_tunnel
(
group_module_ptr
mod
,
std
::
string
id
,
node_id
nid
)
:
super
(
std
::
move
(
mod
),
std
::
move
(
id
),
std
::
move
(
nid
))
{
// nop
}
group_tunnel
::~
group_tunnel
()
{
// nop
}
bool
group_tunnel
::
subscribe
(
strong_actor_ptr
who
)
{
return
critical_section
([
this
,
&
who
]
{
auto
[
added
,
new_size
]
=
subscribe_impl
(
std
::
move
(
who
));
if
(
added
&&
new_size
==
1
)
anon_send
(
worker_
,
sys_atom_v
,
join_atom_v
);
return
added
;
});
}
void
group_tunnel
::
unsubscribe
(
const
actor_control_block
*
who
)
{
return
critical_section
([
this
,
who
]
{
auto
[
removed
,
new_size
]
=
unsubscribe_impl
(
who
);
if
(
removed
&&
new_size
==
0
)
anon_send
(
worker_
,
sys_atom_v
,
leave_atom_v
);
});
}
void
group_tunnel
::
enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
sender
)
<<
CAF_ARG
(
content
));
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
if
(
worker_
!=
nullptr
)
{
auto
wrapped
=
make_message
(
sys_atom_v
,
forward_atom_v
,
std
::
move
(
content
));
worker_
->
enqueue
(
std
::
move
(
sender
),
mid
,
std
::
move
(
wrapped
),
host
);
}
else
if
(
!
stopped_
)
{
auto
wrapped
=
make_message
(
sys_atom_v
,
forward_atom_v
,
std
::
move
(
content
));
cached_messages_
.
emplace_back
(
std
::
move
(
sender
),
mid
,
std
::
move
(
wrapped
));
}
}
void
group_tunnel
::
stop
()
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_DEBUG
(
"stop group tunnel:"
<<
CAF_ARG2
(
"module"
,
module
().
name
())
<<
CAF_ARG2
(
"identifier"
,
identifier_
));
auto
hdl
=
actor
{};
auto
subs
=
subscriber_set
{};
auto
cache
=
cached_message_list
{};
auto
stopped
=
critical_section
([
this
,
&
hdl
,
&
subs
,
&
cache
]
{
using
std
::
swap
;
if
(
!
stopped_
)
{
stopped_
=
true
;
swap
(
subs
,
subscribers_
);
swap
(
hdl
,
worker_
);
swap
(
cache
,
cached_messages_
);
return
true
;
}
else
{
return
false
;
}
});
if
(
stopped
)
{
anon_send_exit
(
hdl
,
exit_reason
::
user_shutdown
);
if
(
!
subs
.
empty
())
{
auto
bye
=
make_message
(
group_down_msg
{
group
{
this
}});
for
(
auto
&
sub
:
subs
)
sub
->
enqueue
(
nullptr
,
make_message_id
(),
bye
,
nullptr
);
}
}
}
std
::
string
group_tunnel
::
stringify
()
const
{
std
::
string
result
;
result
=
"remote:"
;
result
+=
identifier
();
result
+=
'@'
;
result
+=
to_string
(
origin
());
return
result
;
}
void
group_tunnel
::
upstream_enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
sender
)
<<
CAF_ARG
(
content
));
super
::
enqueue
(
std
::
move
(
sender
),
mid
,
std
::
move
(
content
),
host
);
}
bool
group_tunnel
::
connect
(
actor
upstream_intermediary
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
upstream_intermediary
));
return
critical_section
([
this
,
&
upstream_intermediary
]
{
if
(
stopped_
||
worker_
!=
nullptr
)
{
return
false
;
}
else
{
intermediary_
=
upstream_intermediary
;
worker_
=
system
().
spawn
<
group_worker_actor
,
hidden
>
(
this
,
upstream_intermediary
);
if
(
!
subscribers_
.
empty
())
anon_send
(
worker_
,
sys_atom_v
,
join_atom_v
);
for
(
auto
&
[
sender
,
mid
,
content
]
:
cached_messages_
)
worker_
->
enqueue
(
std
::
move
(
sender
),
mid
,
std
::
move
(
content
),
nullptr
);
cached_messages_
.
clear
();
return
true
;
}
});
}
bool
group_tunnel
::
connected
()
const
noexcept
{
return
critical_section
([
this
]
{
return
worker_
!=
nullptr
;
});
}
actor
group_tunnel
::
worker
()
const
noexcept
{
return
critical_section
([
this
]
{
return
worker_
;
});
}
}
// namespace caf::detail
libcaf_core/src/detail/local_group_module.cpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/local_group_module.hpp"
#include "caf/actor_system.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/make_counted.hpp"
#include "caf/send.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/string_algorithms.hpp"
namespace
caf
::
detail
{
// -- local group intermediary -------------------------------------------------
local_group_module
::
intermediary_actor_state
::
intermediary_actor_state
(
event_based_actor
*
self
,
abstract_group_ptr
gptr
)
:
self
(
self
),
gptr
(
std
::
move
(
gptr
))
{
// nop
}
behavior
local_group_module
::
intermediary_actor_state
::
make_behavior
()
{
self
->
set_down_handler
([
this
](
const
down_msg
&
dm
)
{
if
(
auto
ptr
=
dm
.
source
.
get
())
gptr
->
unsubscribe
(
ptr
);
});
return
{
[
this
](
join_atom
,
const
strong_actor_ptr
&
other
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
other
));
if
(
other
)
{
gptr
->
subscribe
(
other
);
self
->
monitor
(
other
);
}
},
[
this
](
leave_atom
,
const
strong_actor_ptr
&
other
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
other
));
if
(
other
)
{
gptr
->
unsubscribe
(
other
.
get
());
self
->
demonitor
(
other
);
}
},
[
this
](
forward_atom
,
const
message
&
what
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
what
));
gptr
->
enqueue
(
self
->
current_sender
(),
make_message_id
(),
what
,
self
->
context
());
},
};
}
// -- local group impl ---------------------------------------------------------
local_group_module
::
impl
::
impl
(
group_module_ptr
mod
,
std
::
string
id
,
node_id
origin
)
:
super
(
mod
,
std
::
move
(
id
),
origin
)
{
// nop
}
local_group_module
::
impl
::
impl
(
group_module_ptr
mod
,
std
::
string
id
)
:
impl
(
mod
,
std
::
move
(
id
),
mod
->
system
().
node
())
{
CAF_LOG_DEBUG
(
"created new local group:"
<<
identifier_
);
}
local_group_module
::
impl
::~
impl
()
{
// nop
}
void
local_group_module
::
impl
::
enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
content
,
execution_unit
*
host
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
for
(
auto
subscriber
:
subscribers_
)
subscriber
->
enqueue
(
sender
,
mid
,
content
,
host
);
}
bool
local_group_module
::
impl
::
subscribe
(
strong_actor_ptr
who
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
return
subscribe_impl
(
who
).
first
;
}
void
local_group_module
::
impl
::
unsubscribe
(
const
actor_control_block
*
who
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
unsubscribe_impl
(
who
);
}
actor
local_group_module
::
impl
::
intermediary
()
const
noexcept
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
return
intermediary_
;
}
void
local_group_module
::
impl
::
stop
()
{
CAF_LOG_DEBUG
(
"stop local group:"
<<
identifier_
);
auto
hdl
=
actor
{};
auto
subs
=
subscriber_set
{};
auto
stopped
=
critical_section
([
this
,
&
hdl
,
&
subs
]
{
using
std
::
swap
;
if
(
!
stopped_
)
{
stopped_
=
true
;
swap
(
subs
,
subscribers_
);
swap
(
hdl
,
intermediary_
);
return
true
;
}
else
{
return
false
;
}
});
if
(
stopped
)
anon_send_exit
(
hdl
,
exit_reason
::
user_shutdown
);
}
std
::
pair
<
bool
,
size_t
>
local_group_module
::
impl
::
subscribe_impl
(
strong_actor_ptr
who
)
{
if
(
!
stopped_
)
{
auto
added
=
subscribers_
.
emplace
(
who
).
second
;
return
{
added
,
subscribers_
.
size
()};
}
else
{
return
{
false
,
subscribers_
.
size
()};
}
}
std
::
pair
<
bool
,
size_t
>
local_group_module
::
impl
::
unsubscribe_impl
(
const
actor_control_block
*
who
)
{
if
(
auto
i
=
subscribers_
.
find
(
who
);
i
!=
subscribers_
.
end
())
{
subscribers_
.
erase
(
i
);
return
{
true
,
subscribers_
.
size
()};
}
else
{
return
{
false
,
subscribers_
.
size
()};
}
}
// -- local group module -------------------------------------------------------
local_group_module
::
local_group_module
(
actor_system
&
sys
)
:
super
(
sys
,
"local"
)
{
// nop
}
local_group_module
::~
local_group_module
()
{
stop
();
}
expected
<
group
>
local_group_module
::
get
(
const
std
::
string
&
group_name
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
if
(
stopped_
)
{
return
make_error
(
sec
::
runtime_error
,
"cannot get a group from on a stopped module"
);
}
else
if
(
auto
i
=
instances_
.
find
(
group_name
);
i
!=
instances_
.
end
())
{
return
group
{
i
->
second
};
}
else
{
auto
ptr
=
make_counted
<
impl
>
(
this
,
group_name
);
ptr
->
intermediary_
=
system
().
spawn
<
intermediary_actor
,
hidden
>
(
ptr
);
instances_
.
emplace
(
group_name
,
ptr
);
return
group
{
ptr
.
release
()};
}
}
void
local_group_module
::
stop
()
{
instances_map
tmp
;
{
using
std
::
swap
;
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
if
(
stopped_
)
return
;
swap
(
instances_
,
tmp
);
stopped_
=
true
;
}
for
(
auto
&
kvp
:
tmp
)
kvp
.
second
->
stop
();
}
}
// namespace caf::detail
libcaf_core/src/group.cpp
View file @
72e62b1a
...
@@ -29,15 +29,7 @@
...
@@ -29,15 +29,7 @@
namespace
caf
{
namespace
caf
{
group
::
group
(
abstract_group
*
ptr
)
:
ptr_
(
ptr
)
{
group
::
group
(
invalid_group_t
)
:
ptr_
(
nullptr
)
{
// nop
}
group
::
group
(
abstract_group
*
ptr
,
bool
add_ref
)
:
ptr_
(
ptr
,
add_ref
)
{
// nop
}
group
::
group
(
const
invalid_group_t
&
)
:
ptr_
(
nullptr
)
{
// nop
// nop
}
}
...
@@ -45,7 +37,7 @@ group::group(abstract_group_ptr gptr) : ptr_(std::move(gptr)) {
...
@@ -45,7 +37,7 @@ group::group(abstract_group_ptr gptr) : ptr_(std::move(gptr)) {
// nop
// nop
}
}
group
&
group
::
operator
=
(
const
invalid_group_t
&
)
{
group
&
group
::
operator
=
(
invalid_group_t
)
{
ptr_
.
reset
();
ptr_
.
reset
();
return
*
this
;
return
*
this
;
}
}
...
@@ -58,13 +50,31 @@ intptr_t group::compare(const group& other) const noexcept {
...
@@ -58,13 +50,31 @@ intptr_t group::compare(const group& other) const noexcept {
return
compare
(
ptr_
.
get
(),
other
.
ptr_
.
get
());
return
compare
(
ptr_
.
get
(),
other
.
ptr_
.
get
());
}
}
expected
<
group
>
group
::
load_impl
(
actor_system
&
sys
,
const
node_id
&
origin
,
const
std
::
string
&
mod
,
const
std
::
string
&
id
)
{
if
(
!
origin
||
origin
==
sys
.
node
())
{
if
(
mod
==
"remote"
)
{
// Local groups on this node appear as remote groups on other nodes.
// Hence, serializing back and forth results in receiving a "remote"
// representation for a group that actually runs locally.
return
sys
.
groups
().
get_local
(
id
);
}
else
{
return
sys
.
groups
().
get
(
mod
,
id
);
}
}
else
if
(
auto
&
get_remote
=
sys
.
groups
().
get_remote
)
{
return
get_remote
(
origin
,
mod
,
id
);
}
else
{
return
make_error
(
sec
::
feature_disabled
,
"cannot access remote group: middleman not loaded"
);
}
}
std
::
string
to_string
(
const
group
&
x
)
{
std
::
string
to_string
(
const
group
&
x
)
{
if
(
x
==
invalid_group
)
if
(
x
)
return
x
.
get
()
->
stringify
();
else
return
"<invalid-group>"
;
return
"<invalid-group>"
;
std
::
string
result
=
x
.
get
()
->
module
().
name
();
result
+=
":"
;
result
+=
x
.
get
()
->
identifier
();
return
result
;
}
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/group_manager.cpp
View file @
72e62b1a
This diff is collapsed.
Click to expand it.
libcaf_core/src/group_module.cpp
View file @
72e62b1a
...
@@ -21,8 +21,7 @@
...
@@ -21,8 +21,7 @@
namespace
caf
{
namespace
caf
{
group_module
::
group_module
(
actor_system
&
sys
,
std
::
string
mname
)
group_module
::
group_module
(
actor_system
&
sys
,
std
::
string
mname
)
:
system_
(
sys
),
:
system_
(
&
sys
),
name_
(
std
::
move
(
mname
))
{
name_
(
std
::
move
(
mname
))
{
// nop
// nop
}
}
...
...
libcaf_core/src/local_actor.cpp
View file @
72e62b1a
...
@@ -119,11 +119,15 @@ void local_actor::monitor(const node_id& node) {
...
@@ -119,11 +119,15 @@ void local_actor::monitor(const node_id& node) {
void
local_actor
::
demonitor
(
const
actor_addr
&
whom
)
{
void
local_actor
::
demonitor
(
const
actor_addr
&
whom
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
whom
));
CAF_LOG_TRACE
(
CAF_ARG
(
whom
));
auto
ptr
=
actor_cast
<
strong_actor_ptr
>
(
whom
);
demonitor
(
actor_cast
<
strong_actor_ptr
>
(
whom
));
if
(
ptr
)
{
}
void
local_actor
::
demonitor
(
const
strong_actor_ptr
&
whom
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
whom
));
if
(
whom
)
{
default_attachable
::
observe_token
tk
{
address
(),
default_attachable
::
observe_token
tk
{
address
(),
default_attachable
::
monitor
};
default_attachable
::
monitor
};
ptr
->
get
()
->
detach
(
tk
);
whom
->
get
()
->
detach
(
tk
);
}
}
}
}
...
...
libcaf_core/test/detail/group_tunnel.cpp
0 → 100644
View file @
72e62b1a
This diff is collapsed.
Click to expand it.
libcaf_core/test/detail/local_group_module.cpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE detail.local_group_module
#include "caf/all.hpp"
#include "core-test.hpp"
#include <algorithm>
#include <array>
#include <chrono>
#include "caf/detail/local_group_module.hpp"
using
namespace
caf
;
namespace
{
struct
testee_state
{
int
x
=
0
;
static
inline
const
char
*
name
=
"testee"
;
};
behavior
testee_impl
(
stateful_actor
<
testee_state
>*
self
)
{
return
{
[
=
](
put_atom
,
int
x
)
{
self
->
state
.
x
=
x
;
},
[
=
](
get_atom
)
{
return
self
->
state
.
x
;
},
};
}
struct
fixture
:
test_coordinator_fixture
<>
{
fixture
()
{
auto
ptr
=
sys
.
groups
().
get_module
(
"local"
);
uut
.
reset
(
dynamic_cast
<
detail
::
local_group_module
*>
(
ptr
.
get
()));
}
~
fixture
()
{
// Groups keep their subscribers alive (on purpose). Since we don't want to
// manually kill all our testee actors, we simply force the group module to
// stop here.
uut
->
stop
();
}
intrusive_ptr
<
detail
::
local_group_module
>
uut
;
};
}
// namespace
CAF_TEST_FIXTURE_SCOPE
(
group_tests
,
fixture
)
CAF_TEST
(
local
groups
are
singletons
)
{
auto
ptr1
=
unbox
(
uut
->
get
(
"test"
));
auto
ptr2
=
unbox
(
uut
->
get
(
"test"
));
CAF_CHECK_EQUAL
(
ptr1
.
get
(),
ptr2
.
get
());
auto
ptr3
=
sys
.
groups
().
get_local
(
"test"
);
CAF_CHECK_EQUAL
(
ptr1
.
get
(),
ptr3
.
get
());
}
CAF_TEST
(
local
groups
forward
messages
to
all
subscribers
)
{
CAF_MESSAGE
(
"Given two subscribers to the group 'test'."
);
auto
grp
=
unbox
(
uut
->
get
(
"test"
));
auto
t1
=
sys
.
spawn_in_group
(
grp
,
testee_impl
);
auto
t2
=
sys
.
spawn_in_group
(
grp
,
testee_impl
);
{
// Subtest.
CAF_MESSAGE
(
"When an actors sends to the group."
);
self
->
send
(
grp
,
put_atom_v
,
42
);
CAF_MESSAGE
(
"Then both subscribers receive the message."
);
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t1
).
with
(
_
,
42
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t2
).
with
(
_
,
42
));
}
{
// Subtest.
CAF_MESSAGE
(
"When an actors leaves the group."
);
CAF_MESSAGE
(
"And an actors sends to the group."
);
grp
->
unsubscribe
(
actor_cast
<
actor_control_block
*>
(
t1
));
self
->
send
(
grp
,
put_atom_v
,
23
);
CAF_MESSAGE
(
"Then only one remaining actor receives the message."
);
disallow
((
put_atom
,
int
),
from
(
self
).
to
(
t1
).
with
(
_
,
23
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t2
).
with
(
_
,
23
));
}
}
CAF_TEST
(
local
group
intermediaries
manage
groups
)
{
CAF_MESSAGE
(
"Given two subscribers to the group 'test'."
);
auto
grp
=
unbox
(
uut
->
get
(
"test"
));
auto
intermediary
=
grp
.
get
()
->
intermediary
();
auto
t1
=
sys
.
spawn_in_group
(
grp
,
testee_impl
);
auto
t2
=
sys
.
spawn_in_group
(
grp
,
testee_impl
);
{
// Subtest.
CAF_MESSAGE
(
"When an actors sends to the group's intermediary."
);
inject
((
forward_atom
,
message
),
from
(
self
)
.
to
(
intermediary
)
.
with
(
forward_atom_v
,
make_message
(
put_atom_v
,
42
)));
CAF_MESSAGE
(
"Then both subscribers receive the message."
);
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t1
).
with
(
_
,
42
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t2
).
with
(
_
,
42
));
}
auto
t3
=
sys
.
spawn
(
testee_impl
);
{
// Subtest.
CAF_MESSAGE
(
"When an actor sends 'join' to the group's intermediary."
);
CAF_MESSAGE
(
"And an actors sends to the group's intermediary."
);
inject
((
join_atom
,
strong_actor_ptr
),
from
(
self
)
.
to
(
intermediary
)
.
with
(
join_atom_v
,
actor_cast
<
strong_actor_ptr
>
(
t3
)));
self
->
send
(
grp
,
put_atom_v
,
23
);
CAF_MESSAGE
(
"Then all three subscribers receive the message."
);
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t1
).
with
(
_
,
23
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t2
).
with
(
_
,
23
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t3
).
with
(
_
,
23
));
}
{
// Subtest.
CAF_MESSAGE
(
"When an actor sends 'leave' to the group's intermediary."
);
CAF_MESSAGE
(
"And an actors sends to the group's intermediary."
);
inject
((
leave_atom
,
strong_actor_ptr
),
from
(
self
)
.
to
(
intermediary
)
.
with
(
leave_atom_v
,
actor_cast
<
strong_actor_ptr
>
(
t3
)));
self
->
send
(
grp
,
put_atom_v
,
37337
);
CAF_MESSAGE
(
"Then only the two remaining subscribers receive the message."
);
self
->
send
(
grp
,
put_atom_v
,
37337
);
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t1
).
with
(
_
,
37337
));
expect
((
put_atom
,
int
),
from
(
self
).
to
(
t2
).
with
(
_
,
37337
));
disallow
((
put_atom
,
int
),
from
(
self
).
to
(
t3
).
with
(
_
,
37337
));
}
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_io/CMakeLists.txt
View file @
72e62b1a
...
@@ -29,6 +29,7 @@ endfunction()
...
@@ -29,6 +29,7 @@ endfunction()
add_library
(
libcaf_io_obj OBJECT
${
CAF_IO_HEADERS
}
add_library
(
libcaf_io_obj OBJECT
${
CAF_IO_HEADERS
}
src/detail/prometheus_broker.cpp
src/detail/prometheus_broker.cpp
src/detail/remote_group_module.cpp
src/detail/socket_guard.cpp
src/detail/socket_guard.cpp
src/io/abstract_broker.cpp
src/io/abstract_broker.cpp
src/io/basp/header.cpp
src/io/basp/header.cpp
...
...
libcaf_io/caf/detail/remote_group_module.hpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/detail/group_tunnel.hpp"
#include "caf/detail/io_export.hpp"
#include "caf/fwd.hpp"
#include "caf/group.hpp"
#include "caf/group_module.hpp"
#include "caf/io/fwd.hpp"
#include <mutex>
#include <string>
#include <unordered_map>
namespace
caf
::
detail
{
class
CAF_IO_EXPORT
remote_group_module
:
public
group_module
{
public:
using
super
=
group_module
;
using
instances_map
=
std
::
unordered_map
<
std
::
string
,
group_tunnel_ptr
>
;
using
nodes_map
=
std
::
unordered_map
<
node_id
,
instances_map
>
;
explicit
remote_group_module
(
io
::
middleman
*
mm
);
void
stop
()
override
;
expected
<
group
>
get
(
const
std
::
string
&
group_name
)
override
;
// Get instance if it exists or create an unconnected tunnel and ask the
// middleman to connect it lazily.
group_tunnel_ptr
get_impl
(
const
node_id
&
origin
,
const
std
::
string
&
group_name
);
// Get instance if it exists or create a connected tunnel.
group_tunnel_ptr
get_impl
(
actor
intermediary
,
const
std
::
string
&
group_name
);
// Get instance if it exists or return `nullptr`.
group_tunnel_ptr
lookup
(
const
node_id
&
origin
,
const
std
::
string
&
group_name
);
private:
template
<
class
F
>
auto
critical_section
(
F
&&
fun
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
return
fun
();
}
// Stops an instance and removes it from this module.
void
drop
(
const
group_tunnel_ptr
&
instance
);
// Connects an instance when it is still associated to this module.
void
connect
(
const
group_tunnel_ptr
&
instance
,
actor
intermediary
);
std
::
function
<
void
(
actor
)
>
make_callback
(
const
group_tunnel_ptr
&
instance
);
// Note: the actor system stops the group module before shutting down the
// middleman. Hence, it's safe to hold onto a raw pointer here.
io
::
middleman
*
mm_
;
std
::
mutex
mtx_
;
bool
stopped_
=
false
;
nodes_map
nodes_
;
};
using
remote_group_module_ptr
=
intrusive_ptr
<
remote_group_module
>
;
}
// namespace caf::detail
libcaf_io/caf/io/middleman.hpp
View file @
72e62b1a
...
@@ -29,6 +29,7 @@
...
@@ -29,6 +29,7 @@
#include "caf/actor_system.hpp"
#include "caf/actor_system.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value.hpp"
#include "caf/detail/io_export.hpp"
#include "caf/detail/io_export.hpp"
#include "caf/detail/remote_group_module.hpp"
#include "caf/detail/unique_function.hpp"
#include "caf/detail/unique_function.hpp"
#include "caf/expected.hpp"
#include "caf/expected.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
...
@@ -111,12 +112,22 @@ public:
...
@@ -111,12 +112,22 @@ public:
return
actor_cast
<
ActorHandle
>
(
std
::
move
(
*
x
));
return
actor_cast
<
ActorHandle
>
(
std
::
move
(
*
x
));
}
}
/// <group-name>@<host>:<port>
/// Tries to connect to a group that runs on a different node in the network.
expected
<
group
>
remote_group
(
const
std
::
string
&
group_uri
);
/// @param group_locator Locator in the format `<group-name>@<host>:<port>`.
expected
<
group
>
remote_group
(
const
std
::
string
&
group_locator
);
/// Tries to connect to a group that runs on a different node in the network.
/// @param group_identifier Unique identifier of the group.
/// @param host Hostname or IP address of the remote CAF node.
/// @param port TCP port for connecting to the group name server of the node.
expected
<
group
>
remote_group
(
const
std
::
string
&
group_identifier
,
expected
<
group
>
remote_group
(
const
std
::
string
&
group_identifier
,
const
std
::
string
&
host
,
uint16_t
port
);
const
std
::
string
&
host
,
uint16_t
port
);
/// @private
void
resolve_remote_group_intermediary
(
const
node_id
&
origin
,
const
std
::
string
&
group_identifier
,
std
::
function
<
void
(
actor
)
>
callback
);
/// Returns the enclosing actor system.
/// Returns the enclosing actor system.
actor_system
&
system
()
{
actor_system
&
system
()
{
return
system_
;
return
system_
;
...
@@ -371,6 +382,9 @@ private:
...
@@ -371,6 +382,9 @@ private:
/// Stores hidden background actors that get killed automatically when the
/// Stores hidden background actors that get killed automatically when the
/// actor systems shuts down.
/// actor systems shuts down.
std
::
list
<
actor
>
background_brokers_
;
std
::
list
<
actor
>
background_brokers_
;
/// Manages groups that run on a different node in the network.
detail
::
remote_group_module_ptr
remote_groups_
;
};
};
}
// namespace caf::io
}
// namespace caf::io
libcaf_io/caf/io/middleman_actor.hpp
View file @
72e62b1a
...
@@ -101,6 +101,8 @@ using middleman_actor = typed_actor<
...
@@ -101,6 +101,8 @@ using middleman_actor = typed_actor<
replies_to
<
spawn_atom
,
node_id
,
std
::
string
,
message
,
replies_to
<
spawn_atom
,
node_id
,
std
::
string
,
message
,
std
::
set
<
std
::
string
>>::
with
<
strong_actor_ptr
>
,
std
::
set
<
std
::
string
>>::
with
<
strong_actor_ptr
>
,
replies_to
<
get_atom
,
group_atom
,
node_id
,
std
::
string
>::
with
<
actor
>
,
replies_to
<
get_atom
,
node_id
>::
with
<
node_id
,
std
::
string
,
uint16_t
>>
;
replies_to
<
get_atom
,
node_id
>::
with
<
node_id
,
std
::
string
,
uint16_t
>>
;
/// Spawns the default implementation for the `middleman_actor` interface.
/// Spawns the default implementation for the `middleman_actor` interface.
...
...
libcaf_io/src/detail/remote_group_module.cpp
0 → 100644
View file @
72e62b1a
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/remote_group_module.hpp"
#include "caf/detail/group_tunnel.hpp"
#include "caf/error.hpp"
#include "caf/expected.hpp"
#include "caf/io/middleman.hpp"
#include "caf/make_counted.hpp"
#include "caf/sec.hpp"
namespace
caf
::
detail
{
remote_group_module
::
remote_group_module
(
io
::
middleman
*
mm
)
:
super
(
mm
->
system
(),
"remote"
),
mm_
(
mm
)
{
// nop
}
void
remote_group_module
::
stop
()
{
nodes_map
tmp
;
critical_section
([
this
,
&
tmp
]
{
using
std
::
swap
;
if
(
!
stopped_
)
{
stopped_
=
true
;
swap
(
nodes_
,
tmp
);
}
});
for
(
auto
&
nodes_kvp
:
tmp
)
for
(
auto
&
instances_kvp
:
nodes_kvp
.
second
)
instances_kvp
.
second
.
get
()
->
stop
();
}
expected
<
group
>
remote_group_module
::
get
(
const
std
::
string
&
group_locator
)
{
return
mm_
->
remote_group
(
group_locator
);
}
group_tunnel_ptr
remote_group_module
::
get_impl
(
const
node_id
&
origin
,
const
std
::
string
&
group_name
)
{
CAF_ASSERT
(
origin
!=
none
);
bool
lazy_connect
=
false
;
auto
instance
=
critical_section
([
&
,
this
]
{
if
(
stopped_
)
{
return
group_tunnel_ptr
{
nullptr
};
}
else
{
auto
&
instances
=
nodes_
[
origin
];
if
(
auto
i
=
instances
.
find
(
group_name
);
i
!=
instances
.
end
())
{
return
i
->
second
;
}
else
{
lazy_connect
=
true
;
auto
instance
=
make_counted
<
detail
::
group_tunnel
>
(
this
,
group_name
,
origin
);
instances
.
emplace
(
group_name
,
instance
);
return
instance
;
}
}
});
if
(
lazy_connect
)
mm_
->
resolve_remote_group_intermediary
(
origin
,
group_name
,
make_callback
(
instance
));
return
instance
;
}
group_tunnel_ptr
remote_group_module
::
get_impl
(
actor
intermediary
,
const
std
::
string
&
group_name
)
{
CAF_ASSERT
(
intermediary
!=
nullptr
);
return
critical_section
([
&
,
this
]()
{
if
(
stopped_
)
{
return
group_tunnel_ptr
{
nullptr
};
}
else
{
auto
&
instances
=
nodes_
[
intermediary
.
node
()];
if
(
auto
i
=
instances
.
find
(
group_name
);
i
!=
instances
.
end
())
{
auto
instance
=
i
->
second
;
instance
->
connect
(
std
::
move
(
intermediary
));
return
instance
;
}
else
{
auto
instance
=
make_counted
<
detail
::
group_tunnel
>
(
this
,
group_name
,
std
::
move
(
intermediary
));
instances
.
emplace
(
group_name
,
instance
);
return
instance
;
}
}
});
}
group_tunnel_ptr
remote_group_module
::
lookup
(
const
node_id
&
origin
,
const
std
::
string
&
group_name
)
{
return
critical_section
([
&
,
this
]
{
if
(
auto
i
=
nodes_
.
find
(
origin
);
i
!=
nodes_
.
end
())
if
(
auto
j
=
i
->
second
.
find
(
group_name
);
j
!=
i
->
second
.
end
())
return
j
->
second
;
return
group_tunnel_ptr
{
nullptr
};
});
}
void
remote_group_module
::
drop
(
const
group_tunnel_ptr
&
instance
)
{
CAF_ASSERT
(
instance
!=
nullptr
);
critical_section
([
&
,
this
]
{
if
(
auto
i
=
nodes_
.
find
(
instance
->
origin
());
i
!=
nodes_
.
end
())
{
if
(
auto
j
=
i
->
second
.
find
(
instance
->
identifier
());
j
!=
i
->
second
.
end
())
{
i
->
second
.
erase
(
j
);
if
(
i
->
second
.
empty
())
nodes_
.
erase
(
i
);
}
}
});
instance
->
stop
();
}
void
remote_group_module
::
connect
(
const
group_tunnel_ptr
&
instance
,
actor
intermediary
)
{
CAF_ASSERT
(
instance
!=
nullptr
);
bool
stop_instance
=
critical_section
([
&
,
this
]
{
if
(
auto
i
=
nodes_
.
find
(
instance
->
origin
());
i
!=
nodes_
.
end
())
{
if
(
auto
j
=
i
->
second
.
find
(
instance
->
identifier
());
j
!=
i
->
second
.
end
()
&&
j
->
second
==
instance
)
{
instance
->
connect
(
intermediary
);
return
false
;
}
}
return
true
;
});
if
(
stop_instance
)
instance
->
stop
();
}
std
::
function
<
void
(
actor
)
>
remote_group_module
::
make_callback
(
const
group_tunnel_ptr
&
instance
)
{
return
[
instance
,
strong_this
{
remote_group_module_ptr
{
this
}}](
actor
hdl
)
{
if
(
hdl
==
nullptr
)
strong_this
->
drop
(
instance
);
else
strong_this
->
connect
(
instance
,
std
::
move
(
hdl
));
};
}
}
// namespace caf::detail
libcaf_io/src/io/middleman.cpp
View file @
72e62b1a
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
#include "caf/detail/set_thread_name.hpp"
#include "caf/detail/set_thread_name.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/function_view.hpp"
#include "caf/function_view.hpp"
#include "caf/group_module.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/io/basp/header.hpp"
#include "caf/io/basp/header.hpp"
#include "caf/io/basp_broker.hpp"
#include "caf/io/basp_broker.hpp"
...
@@ -118,7 +119,7 @@ actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) {
...
@@ -118,7 +119,7 @@ actor_system::module* middleman::make(actor_system& sys, detail::type_list<>) {
}
}
middleman
::
middleman
(
actor_system
&
sys
)
:
system_
(
sys
)
{
middleman
::
middleman
(
actor_system
&
sys
)
:
system_
(
sys
)
{
// nop
remote_groups_
=
make_counted
<
detail
::
remote_group_module
>
(
this
);
}
}
expected
<
strong_actor_ptr
>
expected
<
strong_actor_ptr
>
...
@@ -168,19 +169,20 @@ expected<uint16_t> middleman::publish_local_groups(uint16_t port,
...
@@ -168,19 +169,20 @@ expected<uint16_t> middleman::publish_local_groups(uint16_t port,
CAF_LOG_TRACE
(
CAF_ARG
(
port
)
<<
CAF_ARG
(
in
));
CAF_LOG_TRACE
(
CAF_ARG
(
port
)
<<
CAF_ARG
(
in
));
auto
group_nameserver
=
[](
event_based_actor
*
self
)
->
behavior
{
auto
group_nameserver
=
[](
event_based_actor
*
self
)
->
behavior
{
return
{
return
{
[
self
](
get_atom
,
const
std
::
string
&
name
)
{
[
self
](
get_atom
,
const
std
::
string
&
id
)
{
return
self
->
system
().
groups
().
get_local
(
name
);
auto
grp
=
self
->
system
().
groups
().
get_local
(
id
);
return
grp
.
get
()
->
intermediary
();
},
},
};
};
};
};
auto
gn
=
system
().
spawn
<
hidden
+
lazy_init
>
(
group_nameserver
);
auto
ns
=
system
().
spawn
<
hidden
+
lazy_init
>
(
group_nameserver
);
auto
result
=
publish
(
gn
,
port
,
in
,
reuse
);
if
(
auto
result
=
publish
(
ns
,
port
,
in
,
reuse
))
{
// link gn to our manager
manager_
->
add_link
(
actor_cast
<
abstract_actor
*>
(
ns
));
if
(
result
)
return
*
result
;
manager_
->
add_link
(
actor_cast
<
abstract_actor
*>
(
gn
));
}
else
{
else
anon_send_exit
(
ns
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
gn
,
exit_reason
::
user_shutdown
);
return
std
::
move
(
result
.
error
()
);
return
result
;
}
}
}
expected
<
void
>
middleman
::
unpublish
(
const
actor_addr
&
whom
,
uint16_t
port
)
{
expected
<
void
>
middleman
::
unpublish
(
const
actor_addr
&
whom
,
uint16_t
port
)
{
...
@@ -228,8 +230,8 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
...
@@ -228,8 +230,8 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
CAF_LOG_TRACE
(
CAF_ARG
(
group_identifier
)
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
CAF_LOG_TRACE
(
CAF_ARG
(
group_identifier
)
<<
CAF_ARG
(
host
)
<<
CAF_ARG
(
port
));
// Helper actor that first connects to the remote actor at `host:port` and
// Helper actor that first connects to the remote actor at `host:port` and
// then tries to get a valid group from that actor.
// then tries to get a valid group from that actor.
auto
two_step_lookup
=
[
=
](
event_based_actor
*
self
,
auto
two_step_lookup
=
[
=
](
event_based_actor
*
self
,
middleman_actor
mm
,
middleman_actor
m
m
)
->
behavior
{
detail
::
remote_group_module_ptr
rg
m
)
->
behavior
{
return
{
return
{
[
=
](
get_atom
)
{
[
=
](
get_atom
)
{
/// We won't receive a second message, so we drop our behavior here to
/// We won't receive a second message, so we drop our behavior here to
...
@@ -242,9 +244,12 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
...
@@ -242,9 +244,12 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
CAF_LOG_DEBUG
(
"received handle to target node:"
<<
CAF_ARG
(
ptr
));
CAF_LOG_DEBUG
(
"received handle to target node:"
<<
CAF_ARG
(
ptr
));
auto
hdl
=
actor_cast
<
actor
>
(
ptr
);
auto
hdl
=
actor_cast
<
actor
>
(
ptr
);
self
->
request
(
hdl
,
infinite
,
get_atom_v
,
group_identifier
)
self
->
request
(
hdl
,
infinite
,
get_atom_v
,
group_identifier
)
.
then
([
=
](
group
&
grp
)
mutable
{
.
then
([
=
](
actor
intermediary
)
mutable
{
CAF_LOG_DEBUG
(
"received remote group handle:"
<<
CAF_ARG
(
grp
));
CAF_LOG_DEBUG
(
"lookup successful:"
<<
CAF_ARG
(
group_identifier
)
rp
.
deliver
(
std
::
move
(
grp
));
<<
CAF_ARG
(
intermediary
));
auto
ptr
=
rgm
->
get_impl
(
intermediary
,
group_identifier
);
auto
result
=
group
{
ptr
.
get
()};
rp
.
deliver
(
std
::
move
(
result
));
});
});
});
});
},
},
...
@@ -254,7 +259,8 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
...
@@ -254,7 +259,8 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
expected
<
group
>
result
{
sec
::
cannot_connect_to_node
};
expected
<
group
>
result
{
sec
::
cannot_connect_to_node
};
scoped_actor
self
{
system
(),
true
};
scoped_actor
self
{
system
(),
true
};
auto
worker
=
self
->
spawn
<
lazy_init
+
monitored
>
(
two_step_lookup
,
auto
worker
=
self
->
spawn
<
lazy_init
+
monitored
>
(
two_step_lookup
,
actor_handle
());
actor_handle
(),
remote_groups_
);
self
->
send
(
worker
,
get_atom_v
);
self
->
send
(
worker
,
get_atom_v
);
self
->
receive
(
self
->
receive
(
[
&
](
group
&
grp
)
{
[
&
](
group
&
grp
)
{
...
@@ -272,6 +278,20 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
...
@@ -272,6 +278,20 @@ expected<group> middleman::remote_group(const std::string& group_identifier,
return
result
;
return
result
;
}
}
void
middleman
::
resolve_remote_group_intermediary
(
const
node_id
&
origin
,
const
std
::
string
&
group_identifier
,
std
::
function
<
void
(
actor
)
>
callback
)
{
auto
lookup
=
[
=
,
cb
{
std
::
move
(
callback
)}](
event_based_actor
*
self
,
middleman_actor
mm
)
{
self
->
request
(
mm
,
std
::
chrono
::
minutes
(
1
),
get_atom_v
,
group_atom_v
,
origin
,
group_identifier
)
.
then
([
cb
](
actor
&
hdl
)
{
cb
(
std
::
move
(
hdl
));
},
[
cb
](
const
error
&
)
{
cb
(
actor
{});
});
};
system
().
spawn
(
lookup
,
actor_handle
());
}
strong_actor_ptr
middleman
::
remote_lookup
(
std
::
string
name
,
strong_actor_ptr
middleman
::
remote_lookup
(
std
::
string
name
,
const
node_id
&
nid
)
{
const
node_id
&
nid
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
name
)
<<
CAF_ARG
(
nid
));
CAF_LOG_TRACE
(
CAF_ARG
(
name
)
<<
CAF_ARG
(
nid
));
...
@@ -334,6 +354,19 @@ void middleman::start() {
...
@@ -334,6 +354,19 @@ void middleman::start() {
if
(
auto
prom
=
get_if
<
dict
>
(
&
system
().
config
(),
if
(
auto
prom
=
get_if
<
dict
>
(
&
system
().
config
(),
"caf.middleman.prometheus-http"
))
"caf.middleman.prometheus-http"
))
expose_prometheus_metrics
(
*
prom
);
expose_prometheus_metrics
(
*
prom
);
// Enable deserialization of groups.
system
().
groups
().
get_remote
=
[
this
](
const
node_id
&
origin
,
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
)
->
expected
<
group
>
{
if
(
module_name
==
"local"
||
module_name
==
"remote"
)
{
auto
ptr
=
remote_groups_
->
get_impl
(
origin
,
group_identifier
);
return
group
{
ptr
.
get
()};
}
else
{
return
make_error
(
sec
::
runtime_error
,
"currently, only 'local' groups are accessible remotely"
);
}
};
}
}
void
middleman
::
stop
()
{
void
middleman
::
stop
()
{
...
@@ -388,6 +421,13 @@ void middleman::init(actor_system_config& cfg) {
...
@@ -388,6 +421,13 @@ void middleman::init(actor_system_config& cfg) {
system
().
node_
.
swap
(
this_node
);
system
().
node_
.
swap
(
this_node
);
// Give config access to slave mode implementation.
// Give config access to slave mode implementation.
cfg
.
slave_mode_fun
=
&
middleman
::
exec_slave_mode
;
cfg
.
slave_mode_fun
=
&
middleman
::
exec_slave_mode
;
// Enable users to use 'remote:foo@bar' notation for remote groups.
auto
dummy_fac
=
[
ptr
{
remote_groups_
}]()
->
group_module
*
{
auto
raw
=
ptr
.
get
();
raw
->
ref
();
return
raw
;
};
cfg
.
group_module_factories
.
emplace_back
(
dummy_fac
);
}
}
expected
<
uint16_t
>
middleman
::
expose_prometheus_metrics
(
uint16_t
port
,
expected
<
uint16_t
>
middleman
::
expose_prometheus_metrics
(
uint16_t
port
,
...
...
libcaf_io/src/io/middleman_actor_impl.cpp
View file @
72e62b1a
...
@@ -148,7 +148,7 @@ auto middleman_actor_impl::make_behavior() -> behavior_type {
...
@@ -148,7 +148,7 @@ auto middleman_actor_impl::make_behavior() -> behavior_type {
delegate
(
broker_
,
atm
,
p
);
delegate
(
broker_
,
atm
,
p
);
return
{};
return
{};
},
},
[
=
](
spawn_atom
atm
,
node_id
&
nid
,
std
::
string
&
name
,
message
&
args
,
[
=
](
spawn_atom
,
node_id
&
nid
,
std
::
string
&
name
,
message
&
args
,
std
::
set
<
std
::
string
>&
ifs
)
->
result
<
strong_actor_ptr
>
{
std
::
set
<
std
::
string
>&
ifs
)
->
result
<
strong_actor_ptr
>
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_TRACE
(
""
);
if
(
!
nid
)
if
(
!
nid
)
...
@@ -168,14 +168,25 @@ auto middleman_actor_impl::make_behavior() -> behavior_type {
...
@@ -168,14 +168,25 @@ auto middleman_actor_impl::make_behavior() -> behavior_type {
// reference but spawn_server_id is constexpr).
// reference but spawn_server_id is constexpr).
auto
id
=
basp
::
header
::
spawn_server_id
;
auto
id
=
basp
::
header
::
spawn_server_id
;
delegate
(
broker_
,
forward_atom_v
,
nid
,
id
,
delegate
(
broker_
,
forward_atom_v
,
nid
,
id
,
make_message
(
atm
,
std
::
move
(
name
),
std
::
move
(
args
),
make_message
(
spawn_atom_v
,
std
::
move
(
name
),
std
::
move
(
args
),
std
::
move
(
ifs
)));
std
::
move
(
ifs
)));
return
delegated
<
strong_actor_ptr
>
{};
return
delegated
<
strong_actor_ptr
>
{};
},
},
[
=
](
get_atom
atm
,
[
=
](
get_atom
,
group_atom
,
node_id
&
nid
,
node_id
nid
)
->
delegated
<
node_id
,
std
::
string
,
uint16_t
>
{
std
::
string
&
group_id
)
->
result
<
actor
>
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_TRACE
(
""
);
delegate
(
broker_
,
atm
,
std
::
move
(
nid
));
if
(
!
nid
)
return
make_error
(
sec
::
invalid_argument
,
"cannot get group intermediaries from invalid nodes"
);
auto
id
=
basp
::
header
::
config_server_id
;
delegate
(
broker_
,
forward_atom_v
,
nid
,
id
,
make_message
(
get_atom_v
,
group_atom_v
,
std
::
move
(
nid
),
std
::
move
(
group_id
)));
return
delegated
<
actor
>
{};
},
[
=
](
get_atom
,
node_id
&
nid
)
->
delegated
<
node_id
,
std
::
string
,
uint16_t
>
{
CAF_LOG_TRACE
(
""
);
delegate
(
broker_
,
get_atom_v
,
std
::
move
(
nid
));
return
{};
return
{};
},
},
};
};
...
...
libcaf_io/test/io/remote_group.cpp
View file @
72e62b1a
...
@@ -16,10 +16,11 @@
...
@@ -16,10 +16,11 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#define CAF_SUITE io.remote_group
#include "caf/config.hpp"
#include "caf/config.hpp"
#define CAF_SUITE io_dynamic_remote_group
#include "io-test.hpp"
#include "caf/test/io_dsl.hpp"
#include <algorithm>
#include <algorithm>
#include <vector>
#include <vector>
...
@@ -48,7 +49,9 @@ size_t received_messages = 0u;
...
@@ -48,7 +49,9 @@ size_t received_messages = 0u;
behavior
group_receiver
(
event_based_actor
*
self
)
{
behavior
group_receiver
(
event_based_actor
*
self
)
{
self
->
set_default_handler
(
reflect_and_quit
);
self
->
set_default_handler
(
reflect_and_quit
);
return
{[](
ok_atom
)
{
++
received_messages
;
}};
return
{
[](
ok_atom
)
{
++
received_messages
;
},
};
}
}
// Our server is `mars` and our client is `earth`.
// Our server is `mars` and our client is `earth`.
...
@@ -90,7 +93,7 @@ CAF_TEST(connecting to remote group) {
...
@@ -90,7 +93,7 @@ CAF_TEST(connecting to remote group) {
CAF_CHECK_EQUAL
(
grp
->
get
()
->
identifier
(),
group_name
);
CAF_CHECK_EQUAL
(
grp
->
get
()
->
identifier
(),
group_name
);
}
}
CAF_TEST
_DISABLED
(
message
transmission
)
{
CAF_TEST
(
message
transmission
)
{
CAF_MESSAGE
(
"spawn 5 receivers on mars"
);
CAF_MESSAGE
(
"spawn 5 receivers on mars"
);
auto
mars_grp
=
mars
.
sys
.
groups
().
get_local
(
group_name
);
auto
mars_grp
=
mars
.
sys
.
groups
().
get_local
(
group_name
);
spawn_receivers
(
mars
,
mars_grp
,
5u
);
spawn_receivers
(
mars
,
mars_grp
,
5u
);
...
@@ -102,19 +105,18 @@ CAF_TEST_DISABLED(message transmission) {
...
@@ -102,19 +105,18 @@ CAF_TEST_DISABLED(message transmission) {
auto
earth_grp
=
unbox
(
earth
.
mm
.
remote_group
(
group_name
,
server
,
port
));
auto
earth_grp
=
unbox
(
earth
.
mm
.
remote_group
(
group_name
,
server
,
port
));
CAF_MESSAGE
(
"spawn 5 more receivers on earth"
);
CAF_MESSAGE
(
"spawn 5 more receivers on earth"
);
spawn_receivers
(
earth
,
earth_grp
,
5u
);
spawn_receivers
(
earth
,
earth_grp
,
5u
);
exec_all
();
CAF_MESSAGE
(
"send message on mars and expect 10 handled messages total"
);
CAF_MESSAGE
(
"send message on mars and expect 10 handled messages total"
);
{
{
received_messages
=
0u
;
received_messages
=
0u
;
scoped_actor
self
{
mars
.
sys
};
mars
.
self
->
send
(
mars_grp
,
ok_atom_v
);
self
->
send
(
mars_grp
,
ok_atom_v
);
exec_all
();
exec_all
();
CAF_CHECK_EQUAL
(
received_messages
,
10u
);
CAF_CHECK_EQUAL
(
received_messages
,
10u
);
}
}
CAF_MESSAGE
(
"send message on earth and again expect 10 handled messages"
);
CAF_MESSAGE
(
"send message on earth and again expect 10 handled messages"
);
{
{
received_messages
=
0u
;
received_messages
=
0u
;
scoped_actor
self
{
earth
.
sys
};
earth
.
self
->
send
(
earth_grp
,
ok_atom_v
);
self
->
send
(
earth_grp
,
ok_atom_v
);
exec_all
();
exec_all
();
CAF_CHECK_EQUAL
(
received_messages
,
10u
);
CAF_CHECK_EQUAL
(
received_messages
,
10u
);
}
}
...
...
libcaf_test/caf/test/dsl.hpp
View file @
72e62b1a
...
@@ -458,24 +458,24 @@ public:
...
@@ -458,24 +458,24 @@ public:
void
with
(
Ts
...
xs
)
{
void
with
(
Ts
...
xs
)
{
if
(
dest_
==
nullptr
)
if
(
dest_
==
nullptr
)
CAF_FAIL
(
"missing .to() in inject() statement"
);
CAF_FAIL
(
"missing .to() in inject() statement"
);
auto
msg
=
caf
::
make_message
(
std
::
move
(
xs
)...);
if
(
src_
==
nullptr
)
if
(
src_
==
nullptr
)
caf
::
anon_send
(
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...
);
caf
::
anon_send
(
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
msg
);
else
else
caf
::
send_as
(
caf
::
actor_cast
<
caf
::
actor
>
(
src_
),
caf
::
send_as
(
caf
::
actor_cast
<
caf
::
actor
>
(
src_
),
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
xs
...);
caf
::
actor_cast
<
caf
::
actor
>
(
dest_
),
msg
);
CAF_REQUIRE
(
sched_
.
prioritize
(
dest_
));
if
(
!
sched_
.
prioritize
(
dest_
))
CAF_FAIL
(
"inject: failed to schedule destination actor"
);
auto
dest_ptr
=
&
sched_
.
next_job
<
caf
::
abstract_actor
>
();
auto
dest_ptr
=
&
sched_
.
next_job
<
caf
::
abstract_actor
>
();
auto
ptr
=
dest_ptr
->
peek_at_next_mailbox_element
();
auto
ptr
=
dest_ptr
->
peek_at_next_mailbox_element
();
CAF_REQUIRE
(
ptr
!=
nullptr
);
if
(
ptr
==
nullptr
)
CAF_REQUIRE_EQUAL
(
ptr
->
sender
,
src_
);
CAF_FAIL
(
"inject: failed to get next message from destination actor"
);
// TODO: replace this workaround with the make_tuple() line when dropping
if
(
ptr
->
sender
!=
src_
)
// support for GCC 4.8.
CAF_FAIL
(
"inject: found unexpected sender for the next message"
);
std
::
tuple
<
Ts
...
>
tmp
{
std
::
move
(
xs
)...};
if
(
ptr
->
payload
.
cptr
()
!=
msg
.
cptr
())
using
namespace
caf
::
detail
;
CAF_FAIL
(
"inject: found unexpected message => "
<<
ptr
->
payload
<<
" !! "
elementwise_compare_inspector
<
decltype
(
tmp
)
>
inspector
{
tmp
};
<<
msg
);
auto
ys
=
extract
<
Ts
...
>
(
dest_
);
msg
.
reset
();
// drop local reference before running the actor
auto
ys_indices
=
get_indices
(
ys
);
CAF_REQUIRE
(
apply_args
(
inspector
,
ys_indices
,
ys
));
run_once
();
run_once
();
}
}
...
...
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