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
cf9a69e3
Commit
cf9a69e3
authored
Nov 09, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-implement the local group module
parent
c9cc5d42
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
594 additions
and
515 deletions
+594
-515
examples/remoting/group_chat.cpp
examples/remoting/group_chat.cpp
+29
-40
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+2
-1
libcaf_core/caf/abstract_group.hpp
libcaf_core/caf/abstract_group.hpp
+16
-14
libcaf_core/caf/detail/local_group_module.hpp
libcaf_core/caf/detail/local_group_module.hpp
+103
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+2
-1
libcaf_core/caf/group.hpp
libcaf_core/caf/group.hpp
+24
-17
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/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/src/abstract_group.cpp
libcaf_core/src/abstract_group.cpp
+25
-10
libcaf_core/src/detail/local_group_module.cpp
libcaf_core/src/detail/local_group_module.cpp
+158
-0
libcaf_core/src/group.cpp
libcaf_core/src/group.cpp
+14
-4
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/test/detail/local_group_module.cpp
libcaf_core/test/detail/local_group_module.cpp
+144
-0
No files found.
examples/remoting/group_chat.cpp
View file @
cf9a69e3
...
@@ -104,53 +104,42 @@ void run_client(actor_system& system, const config& cfg) {
...
@@ -104,53 +104,42 @@ 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
=
system
.
spawn
(
client
,
name
);
auto
client_actor
=
system
.
spawn
(
client
,
name
);
for
(
auto
&
uri
:
cfg
.
group_uris
)
{
for
(
auto
&
uri
:
cfg
.
group_uris
)
{
auto
tmp
=
system
.
groups
().
get
(
uri
);
if
(
auto
grp
=
system
.
groups
().
get
(
uri
))
{
if
(
tmp
)
std
::
cout
<<
"*** join "
<<
to_string
(
grp
)
<<
'\n'
;
anon_send
(
client_actor
,
join_atom_v
,
std
::
move
(
*
tm
p
));
anon_send
(
client_actor
,
join_atom_v
,
std
::
move
(
*
gr
p
));
else
}
else
{
std
::
cerr
<<
R"(*** failed to parse ")"
<<
uri
<<
R"(" as group URI: )"
std
::
cerr
<<
R"(*** failed to parse ")"
<<
uri
<<
R"(" as group URI: )"
<<
to_string
(
tmp
.
error
())
<<
std
::
endl
;
<<
to_string
(
grp
.
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
(
" "
));
message_handler
f
{
if
(
words
.
size
()
==
3
&&
words
[
0
]
==
"/join"
)
{
[
&
](
const
std
::
string
&
cmd
,
const
std
::
string
&
mod
,
if
(
auto
grp
=
system
.
groups
().
get
(
words
[
1
],
words
[
2
]))
const
std
::
string
&
id
)
{
if
(
cmd
==
"/join"
)
{
auto
grp
=
system
.
groups
().
get
(
mod
,
id
);
if
(
grp
)
anon_send
(
client_actor
,
join_atom_v
,
*
grp
);
anon_send
(
client_actor
,
join_atom_v
,
*
grp
);
}
else
{
else
send_input
();
std
::
cerr
<<
"*** failed to join group: "
<<
to_string
(
grp
.
error
())
}
<<
std
::
endl
;
},
}
else
if
(
words
.
size
()
==
1
&&
words
[
0
]
==
"quit"
)
{
[
&
](
const
std
::
string
&
cmd
)
{
if
(
cmd
==
"/quit"
)
{
std
::
cin
.
setstate
(
std
::
ios_base
::
eofbit
);
std
::
cin
.
setstate
(
std
::
ios_base
::
eofbit
);
}
else
if
(
cmd
[
0
]
==
'/'
)
{
}
else
{
std
::
cout
<<
"*** available commands:
\n
"
std
::
cout
<<
"*** available commands:
\n
"
" /join <module> <group> join a new chat channel
\n
"
" /join <module> <group> join a new chat channel
\n
"
" /quit quit the program
\n
"
" /quit quit the program
\n
"
" /help print this text
\n
"
;
" /help print this text
\n
"
;
}
}
else
{
}
else
{
send_input
(
);
anon_send
(
client_actor
,
broadcast_atom_v
,
i
->
str
);
}
}
},
};
auto
msg
=
message_builder
(
words
.
begin
(),
words
.
end
()).
move_to_message
();
auto
res
=
f
(
msg
);
if
(
!
res
)
send_input
();
}
}
// force actor to quit
// force actor to quit
anon_send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
anon_send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
...
...
libcaf_core/CMakeLists.txt
View file @
cf9a69e3
...
@@ -87,6 +87,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
...
@@ -87,6 +87,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/get_root_uuid.cpp
src/detail/get_root_uuid.cpp
src/detail/glob_match.cpp
src/detail/glob_match.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
...
@@ -248,6 +249,7 @@ caf_add_test_suites(caf-core-test
...
@@ -248,6 +249,7 @@ caf_add_test_suites(caf-core-test
detail.encode_base64
detail.encode_base64
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
...
@@ -290,7 +292,6 @@ caf_add_test_suites(caf-core-test
...
@@ -290,7 +292,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 @
cf9a69e3
...
@@ -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
to_string
()
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/local_group_module.h
pp
View file @
cf9a69e3
...
@@ -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,88 @@
...
@@ -16,71 +16,88 @@
* 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 <functional>
#include <mutex>
#include <set>
#include <unordered_map>
#include "core-test.hpp"
#include "caf/abstract_group.hpp"
#include "caf/group_module.hpp"
#include <array>
namespace
caf
::
detail
{
#include <chrono>
#include <algorithm>
using
namespace
caf
;
/// 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
local_group_module
:
public
group_module
{
public:
using
super
=
group_module
;
namespace
{
struct
intermediary_actor_state
{
static
inline
const
char
*
name
=
"caf.detail.group-intermediary"
;
using
testee_if
intermediary_actor_state
(
event_based_actor
*
self
,
abstract_group_ptr
gptr
);
=
typed_actor
<
replies_to
<
get_atom
>::
with
<
int
>
,
reacts_to
<
put_atom
,
int
>>
;
struct
testee_state
{
behavior
make_behavior
();
int
x
=
0
;
}
;
event_based_actor
*
self
;
behavior
testee_impl
(
stateful_actor
<
testee_state
>*
self
)
{
abstract_group_ptr
gptr
;
auto
subscriptions
=
self
->
joined_groups
();
return
{
[
=
](
put_atom
,
int
x
)
{
self
->
state
.
x
=
x
;
},
[
=
](
get_atom
)
{
return
self
->
state
.
x
;
}
};
};
}
struct
fixture
{
/// A group intermediary enables remote actors to join and leave groups on
actor_system_config
config
;
/// this endpoint as well as sending message to it.
actor_system
system
{
config
};
using
intermediary_actor
=
stateful_actor
<
intermediary_actor_state
>
;
scoped_actor
self
{
system
};
};
/// Implementation of the group interface for instances of this module.
class
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
);
~
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
;
}
// namespace
actor
intermediary
()
const
noexcept
override
;
CAF_TEST_FIXTURE_SCOPE
(
group_tests
,
fixture
)
void
stop
()
override
;
CAF_TEST
(
class_based_joined_at_spawn
)
{
protected:
auto
grp
=
system
.
groups
().
get_local
(
"test"
);
mutable
std
::
mutex
mtx_
;
// initialize all testee actors, spawning them in the group
actor
intermediary_
;
std
::
array
<
actor
,
10
>
xs
;
bool
stopped_
=
false
;
for
(
auto
&
x
:
xs
)
subscriber_set
subscribers_
;
x
=
system
.
spawn_in_group
(
grp
,
testee_impl
);
};
// get a function view for all testees
std
::
array
<
function_view
<
testee_if
>
,
10
>
fs
;
using
instances_map
=
std
::
unordered_map
<
std
::
string
,
intrusive_ptr
<
impl
>>
;
std
::
transform
(
xs
.
begin
(),
xs
.
end
(),
fs
.
begin
(),
[](
const
actor
&
x
)
{
return
make_function_view
(
actor_cast
<
testee_if
>
(
x
));
explicit
local_group_module
(
actor_system
&
sys
);
});
// make sure all actors start at 0
~
local_group_module
()
override
;
for
(
auto
&
f
:
fs
)
CAF_CHECK_EQUAL
(
f
(
get_atom_v
),
0
);
expected
<
group
>
get
(
const
std
::
string
&
group_name
)
override
;
// send a put to all actors via the group and make sure they change state
self
->
send
(
grp
,
put_atom_v
,
42
);
void
stop
()
override
;
for
(
auto
&
f
:
fs
)
CAF_CHECK_EQUAL
(
f
(
get_atom_v
),
42
);
private:
// shutdown all actors
std
::
mutex
mtx_
;
for
(
auto
&
x
:
xs
)
bool
stopped_
=
false
;
self
->
send_exit
(
x
,
exit_reason
::
user_shutdown
);
instances_map
instances_
;
}
};
CAF_TEST_FIXTURE_SCOPE_END
()
}
// namespace caf::detail
libcaf_core/caf/fwd.hpp
View file @
cf9a69e3
...
@@ -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 @
cf9a69e3
...
@@ -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
;
...
@@ -60,7 +61,7 @@ public:
...
@@ -60,7 +61,7 @@ public:
group
&
operator
=
(
const
invalid_group_t
&
);
group
&
operator
=
(
const
invalid_group_t
&
);
group
(
abstract_group
*
);
explicit
group
(
abstract_group
*
);
group
(
intrusive_ptr
<
abstract_group
>
gptr
);
group
(
intrusive_ptr
<
abstract_group
>
gptr
);
...
@@ -76,7 +77,11 @@ public:
...
@@ -76,7 +77,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 +121,20 @@ public:
...
@@ -116,22 +121,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
{
...
@@ -145,14 +148,18 @@ public:
...
@@ -145,14 +148,18 @@ public:
};
};
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 @
cf9a69e3
...
@@ -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 @
cf9a69e3
...
@@ -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/message.hpp
View file @
cf9a69e3
...
@@ -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 @
cf9a69e3
...
@@ -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/src/abstract_group.cpp
View file @
cf9a69e3
...
@@ -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
,
node_id
nid
)
:
abstract_channel
(
abstract_channel
::
is_abstract_group_flag
),
:
abstract_channel
(
abstract_channel
::
is_abstract_group_flag
),
system_
(
mod
.
system
()),
parent_
(
std
::
move
(
mod
)),
parent_
(
mod
),
origin_
(
std
::
move
(
nid
)),
identifier_
(
std
::
move
(
id
)),
identifier_
(
std
::
move
(
id
))
{
origin_
(
std
::
move
(
nid
))
{
// 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
::
to_string
()
const
{
auto
result
=
module
().
name
();
result
+=
':'
;
result
+=
identifier
();
return
result
;
}
actor
abstract_group
::
intermediary
()
const
noexcept
{
return
{};
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/detail/local_group_module.cpp
0 → 100644
View file @
cf9a69e3
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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
)
:
super
(
mod
,
std
::
move
(
id
),
mod
->
system
().
node
())
{
CAF_LOG_DEBUG
(
"created new local group:"
<<
identifier_
);
}
local_group_module
::
impl
::~
impl
()
{
CAF_LOG_DEBUG
(
"destroyed local group:"
<<
identifier_
);
}
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
!
stopped_
&&
subscribers_
.
emplace
(
who
).
second
;
}
void
local_group_module
::
impl
::
unsubscribe
(
const
actor_control_block
*
who
)
{
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
// Note: can't call erase with `who` directly, because only set::find has an
// overload for any K that is less-comparable to Key.
if
(
auto
i
=
subscribers_
.
find
(
who
);
i
!=
subscribers_
.
end
())
subscribers_
.
erase
(
i
);
}
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
{};
{
using
std
::
swap
;
std
::
unique_lock
<
std
::
mutex
>
guard
{
mtx_
};
if
(
stopped_
)
return
;
stopped_
=
true
;
swap
(
subs
,
subscribers_
);
swap
(
hdl
,
intermediary_
);
}
anon_send_exit
(
hdl
,
exit_reason
::
user_shutdown
);
}
// -- 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
.
get
()};
}
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 @
cf9a69e3
...
@@ -58,13 +58,23 @@ intptr_t group::compare(const group& other) const noexcept {
...
@@ -58,13 +58,23 @@ 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
())
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
==
invalid_group
)
return
"<invalid-group>"
;
return
"<invalid-group>"
;
std
::
string
result
=
x
.
get
()
->
module
().
name
();
else
result
+=
":"
;
return
x
.
get
()
->
to_string
();
result
+=
x
.
get
()
->
identifier
();
return
result
;
}
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/group_manager.cpp
View file @
cf9a69e3
...
@@ -16,17 +16,12 @@
...
@@ -16,17 +16,12 @@
* http://www.boost.org/LICENSE_1_0.txt. *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
******************************************************************************/
#include <condition_variable>
#include "caf/group_manager.hpp"
#include <mutex>
#include <set>
#include <sstream>
#include <stdexcept>
#include "caf/all.hpp"
#include "caf/all.hpp"
#include "caf/deserializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/local_group_module.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/group.hpp"
#include "caf/group.hpp"
#include "caf/group_manager.hpp"
#include "caf/locks.hpp"
#include "caf/locks.hpp"
#include "caf/message.hpp"
#include "caf/message.hpp"
#include "caf/sec.hpp"
#include "caf/sec.hpp"
...
@@ -34,369 +29,12 @@
...
@@ -34,369 +29,12 @@
namespace
caf
{
namespace
caf
{
namespace
{
using
exclusive_guard
=
unique_lock
<
detail
::
shared_spinlock
>
;
using
shared_guard
=
shared_lock
<
detail
::
shared_spinlock
>
;
using
upgrade_guard
=
upgrade_lock
<
detail
::
shared_spinlock
>
;
using
upgrade_to_unique_guard
=
upgrade_to_unique_lock
<
detail
::
shared_spinlock
>
;
class
local_dispatcher
;
class
local_group_module
;
void
await_all_locals_down
(
actor_system
&
sys
,
std
::
initializer_list
<
actor
>
xs
)
{
CAF_LOG_TRACE
(
""
);
scoped_actor
self
{
sys
,
true
};
std
::
vector
<
actor
>
ys
;
for
(
auto
&
x
:
xs
)
if
(
x
.
node
()
==
sys
.
node
())
{
self
->
send_exit
(
x
,
exit_reason
::
kill
);
ys
.
push_back
(
x
);
}
// Don't block when using the test coordinator.
if
(
auto
policy
=
get_if
<
std
::
string
>
(
&
sys
.
config
(),
"caf.scheduler.policy"
);
policy
&&
*
policy
!=
"testing"
)
self
->
wait_for
(
ys
);
}
class
local_group
:
public
abstract_group
{
public:
void
send_all_subscribers
(
const
strong_actor_ptr
&
sender
,
const
message
&
msg
,
execution_unit
*
host
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
sender
)
<<
CAF_ARG
(
msg
));
shared_guard
guard
(
mtx_
);
for
(
auto
&
s
:
subscribers_
)
s
->
enqueue
(
sender
,
make_message_id
(),
msg
,
host
);
}
void
enqueue
(
strong_actor_ptr
sender
,
message_id
,
message
msg
,
execution_unit
*
host
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
sender
)
<<
CAF_ARG
(
msg
));
send_all_subscribers
(
sender
,
msg
,
host
);
dispatcher_
->
enqueue
(
sender
,
make_message_id
(),
msg
,
host
);
}
std
::
pair
<
bool
,
size_t
>
add_subscriber
(
strong_actor_ptr
who
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
who
));
if
(
!
who
)
return
{
false
,
subscribers_
.
size
()};
exclusive_guard
guard
(
mtx_
);
auto
res
=
subscribers_
.
emplace
(
std
::
move
(
who
)).
second
;
return
{
res
,
subscribers_
.
size
()};
}
std
::
pair
<
bool
,
size_t
>
erase_subscriber
(
const
actor_control_block
*
who
)
{
CAF_LOG_TRACE
(
""
);
// serializing who would cause a deadlock
exclusive_guard
guard
(
mtx_
);
auto
e
=
subscribers_
.
end
();
auto
cmp
=
[
&
](
const
strong_actor_ptr
&
lhs
)
{
return
lhs
.
get
()
==
who
;
};
auto
i
=
std
::
find_if
(
subscribers_
.
begin
(),
e
,
cmp
);
if
(
i
==
e
)
return
{
false
,
subscribers_
.
size
()};
subscribers_
.
erase
(
i
);
return
{
true
,
subscribers_
.
size
()};
}
bool
subscribe
(
strong_actor_ptr
who
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
who
));
return
add_subscriber
(
std
::
move
(
who
)).
first
;
}
void
unsubscribe
(
const
actor_control_block
*
who
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
who
));
erase_subscriber
(
who
);
}
void
stop
()
override
{
CAF_LOG_TRACE
(
""
);
await_all_locals_down
(
system
(),
{
dispatcher_
});
}
local_group
(
local_group_module
&
mod
,
std
::
string
id
,
node_id
nid
,
optional
<
actor
>
lb
);
~
local_group
()
override
;
protected:
detail
::
shared_spinlock
mtx_
;
#if __cplusplus > 201103L
std
::
set
<
strong_actor_ptr
,
std
::
less
<>>
subscribers_
;
#else
std
::
set
<
strong_actor_ptr
>
subscribers_
;
#endif
actor
dispatcher_
;
};
using
local_group_ptr
=
intrusive_ptr
<
local_group
>
;
class
local_dispatcher
:
public
event_based_actor
{
public:
explicit
local_dispatcher
(
actor_config
&
cfg
,
local_group_ptr
g
)
:
event_based_actor
(
cfg
),
group_
(
std
::
move
(
g
))
{
// nop
}
void
on_exit
()
override
{
acquaintances_
.
clear
();
group_
.
reset
();
}
const
char
*
name
()
const
override
{
return
"local_dispatcher"
;
}
behavior
make_behavior
()
override
{
CAF_LOG_TRACE
(
""
);
// instead of dropping "unexpected" messages,
// we simply forward them to our acquaintances
auto
fwd
=
[
=
](
scheduled_actor
*
,
message
&
msg
)
->
skippable_result
{
send_to_acquaintances
(
std
::
move
(
msg
));
return
delegated
<
message
>
{};
};
set_default_handler
(
fwd
);
set_down_handler
([
=
](
down_msg
&
dm
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
dm
));
auto
first
=
acquaintances_
.
begin
();
auto
last
=
acquaintances_
.
end
();
auto
i
=
std
::
find_if
(
first
,
last
,
[
&
](
const
actor
&
a
)
{
return
a
==
dm
.
source
;
});
if
(
i
!=
last
)
acquaintances_
.
erase
(
i
);
});
// return behavior
return
{[
=
](
join_atom
,
const
actor
&
other
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
other
));
if
(
acquaintances_
.
insert
(
other
).
second
)
{
monitor
(
other
);
}
},
[
=
](
leave_atom
,
const
actor
&
other
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
other
));
acquaintances_
.
erase
(
other
);
if
(
acquaintances_
.
erase
(
other
)
>
0
)
demonitor
(
other
);
},
[
=
](
forward_atom
,
const
message
&
what
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
what
));
// local forwarding
group_
->
send_all_subscribers
(
current_element_
->
sender
,
what
,
context
());
// forward to all acquaintances
send_to_acquaintances
(
what
);
}};
}
private:
void
send_to_acquaintances
(
const
message
&
what
)
{
// send to all remote subscribers
auto
src
=
current_element_
->
sender
;
CAF_LOG_DEBUG
(
CAF_ARG
(
acquaintances_
.
size
())
<<
CAF_ARG
(
src
)
<<
CAF_ARG
(
what
));
for
(
auto
&
acquaintance
:
acquaintances_
)
acquaintance
->
enqueue
(
src
,
make_message_id
(),
what
,
context
());
}
local_group_ptr
group_
;
std
::
set
<
actor
>
acquaintances_
;
};
// Send a join message to the original group if a proxy
// has local subscriptions and a "LEAVE" message to the original group
// if there's no subscription left.
class
local_group_proxy
;
using
local_group_proxy_ptr
=
intrusive_ptr
<
local_group_proxy
>
;
class
proxy_dispatcher
:
public
event_based_actor
{
public:
proxy_dispatcher
(
actor_config
&
cfg
,
local_group_proxy_ptr
grp
)
:
event_based_actor
(
cfg
),
group_
(
std
::
move
(
grp
))
{
CAF_LOG_TRACE
(
""
);
}
behavior
make_behavior
()
override
;
void
on_exit
()
override
{
group_
.
reset
();
}
private:
local_group_proxy_ptr
group_
;
};
class
local_group_proxy
:
public
local_group
{
public:
local_group_proxy
(
actor_system
&
sys
,
actor
remote_dispatcher
,
local_group_module
&
mod
,
std
::
string
id
,
node_id
nid
)
:
local_group
(
mod
,
std
::
move
(
id
),
std
::
move
(
nid
),
std
::
move
(
remote_dispatcher
)),
proxy_dispatcher_
{
sys
.
spawn
<
proxy_dispatcher
,
hidden
>
(
this
)},
monitor_
{
sys
.
spawn
<
hidden
>
(
dispatcher_monitor_actor
,
this
)}
{
// nop
}
bool
subscribe
(
strong_actor_ptr
who
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
who
));
auto
res
=
add_subscriber
(
std
::
move
(
who
));
if
(
res
.
first
)
{
// join remote source
if
(
res
.
second
==
1
)
anon_send
(
dispatcher_
,
join_atom_v
,
proxy_dispatcher_
);
return
true
;
}
CAF_LOG_WARNING
(
"actor already joined group"
);
return
false
;
}
void
unsubscribe
(
const
actor_control_block
*
who
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
who
));
auto
res
=
erase_subscriber
(
who
);
if
(
res
.
first
&&
res
.
second
==
0
)
{
// leave the remote source,
// because there's no more subscriber on this node
anon_send
(
dispatcher_
,
leave_atom_v
,
proxy_dispatcher_
);
}
}
void
enqueue
(
strong_actor_ptr
sender
,
message_id
mid
,
message
msg
,
execution_unit
*
eu
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
sender
)
<<
CAF_ARG
(
mid
)
<<
CAF_ARG
(
msg
));
// forward message to the dispatcher
dispatcher_
->
enqueue
(
std
::
move
(
sender
),
mid
,
make_message
(
forward_atom_v
,
std
::
move
(
msg
)),
eu
);
}
void
stop
()
override
{
CAF_LOG_TRACE
(
""
);
await_all_locals_down
(
system_
,
{
monitor_
,
proxy_dispatcher_
,
dispatcher_
});
}
private:
static
behavior
dispatcher_monitor_actor
(
event_based_actor
*
self
,
local_group_proxy
*
grp
)
{
CAF_LOG_TRACE
(
""
);
self
->
monitor
(
grp
->
dispatcher_
);
self
->
set_down_handler
([
=
](
down_msg
&
down
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
down
));
auto
msg
=
make_message
(
group_down_msg
{
group
(
grp
)});
grp
->
send_all_subscribers
(
self
->
ctrl
(),
std
::
move
(
msg
),
self
->
context
());
self
->
quit
(
down
.
reason
);
});
return
{[]
{
// nop
}};
}
actor
proxy_dispatcher_
;
actor
monitor_
;
};
behavior
proxy_dispatcher
::
make_behavior
()
{
CAF_LOG_TRACE
(
""
);
// instead of dropping "unexpected" messages,
// we simply forward them to our acquaintances
auto
fwd
=
[
=
](
local_actor
*
,
message
&
msg
)
->
skippable_result
{
group_
->
send_all_subscribers
(
current_element_
->
sender
,
std
::
move
(
msg
),
context
());
return
message
{};
};
set_default_handler
(
fwd
);
// return dummy behavior
return
{[]
{
// nop
}};
}
class
local_group_module
:
public
group_module
{
public:
local_group_module
(
actor_system
&
sys
)
:
group_module
(
sys
,
"local"
)
{
CAF_LOG_TRACE
(
""
);
}
expected
<
group
>
get
(
const
std
::
string
&
identifier
)
override
{
CAF_LOG_TRACE
(
CAF_ARG
(
identifier
));
upgrade_guard
guard
(
instances_mtx_
);
auto
i
=
instances_
.
find
(
identifier
);
if
(
i
!=
instances_
.
end
())
return
group
{
i
->
second
};
auto
tmp
=
make_counted
<
local_group
>
(
*
this
,
identifier
,
system
().
node
(),
none
);
upgrade_to_unique_guard
uguard
(
guard
);
auto
p
=
instances_
.
emplace
(
identifier
,
tmp
);
auto
result
=
p
.
first
->
second
;
uguard
.
unlock
();
// someone might preempt us
if
(
result
!=
tmp
)
tmp
->
stop
();
return
group
{
result
};
}
expected
<
group
>
get
(
const
std
::
string
&
identifier
,
const
caf
::
actor
&
dispatcher
)
override
{
CAF_LOG_DEBUG
(
CAF_ARG
(
identifier
)
<<
CAF_ARG
(
dispatcher
));
if
(
!
dispatcher
)
return
make_error
(
sec
::
invalid_argument
,
"dispatcher == nullptr"
);
if
(
dispatcher
->
node
()
==
system
().
node
())
return
get
(
identifier
);
upgrade_guard
guard
(
proxies_mtx_
);
auto
i
=
proxies_
.
find
(
dispatcher
);
if
(
i
!=
proxies_
.
end
())
return
group
{
i
->
second
};
local_group_ptr
tmp
=
make_counted
<
local_group_proxy
>
(
system
(),
dispatcher
,
*
this
,
identifier
,
dispatcher
->
node
());
upgrade_to_unique_guard
uguard
(
guard
);
auto
p
=
proxies_
.
emplace
(
dispatcher
,
tmp
);
// someone might preempt us
return
group
{
p
.
first
->
second
};
}
void
stop
()
override
{
CAF_LOG_TRACE
(
""
);
std
::
map
<
std
::
string
,
local_group_ptr
>
imap
;
std
::
map
<
actor
,
local_group_ptr
>
pmap
;
{
// critical section
exclusive_guard
guard1
{
instances_mtx_
};
exclusive_guard
guard2
{
proxies_mtx_
};
imap
.
swap
(
instances_
);
pmap
.
swap
(
proxies_
);
}
for
(
auto
&
kvp
:
imap
)
kvp
.
second
->
stop
();
for
(
auto
&
kvp
:
pmap
)
kvp
.
second
->
stop
();
}
private:
detail
::
shared_spinlock
instances_mtx_
;
std
::
map
<
std
::
string
,
local_group_ptr
>
instances_
;
detail
::
shared_spinlock
proxies_mtx_
;
std
::
map
<
actor
,
local_group_ptr
>
proxies_
;
};
local_group
::
local_group
(
local_group_module
&
mod
,
std
::
string
id
,
node_id
nid
,
optional
<
actor
>
lb
)
:
abstract_group
(
mod
,
std
::
move
(
id
),
std
::
move
(
nid
))
{
CAF_LOG_TRACE
(
CAF_ARG
(
id
)
<<
CAF_ARG
(
nid
));
dispatcher_
=
lb
?
*
lb
:
mod
.
system
().
spawn
<
local_dispatcher
,
hidden
>
(
this
);
}
local_group
::~
local_group
()
{
// nop
}
std
::
atomic
<
size_t
>
s_ad_hoc_id
;
}
// namespace
void
group_manager
::
init
(
actor_system_config
&
cfg
)
{
void
group_manager
::
init
(
actor_system_config
&
cfg
)
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_TRACE
(
""
);
using
ptr_type
=
std
::
unique_ptr
<
group_module
>
;
mmap_
.
emplace
(
"local"
,
make_counted
<
detail
::
local_group_module
>
(
*
system_
));
mmap_
.
emplace
(
"local"
,
ptr_type
{
new
local_group_module
(
system_
)});
for
(
auto
&
fac
:
cfg
.
group_module_factories
)
{
for
(
auto
&
fac
:
cfg
.
group_module_factories
)
{
ptr_type
ptr
{
fac
()
};
auto
ptr
=
group_module_ptr
{
fac
(),
false
};
std
::
string
name
=
ptr
->
name
();
auto
name
=
ptr
->
name
();
mmap_
.
emplace
(
std
::
move
(
name
),
std
::
move
(
ptr
));
mmap_
.
emplace
(
std
::
move
(
name
),
std
::
move
(
ptr
));
}
}
}
}
...
@@ -415,19 +53,18 @@ group_manager::~group_manager() {
...
@@ -415,19 +53,18 @@ group_manager::~group_manager() {
// nop
// nop
}
}
group_manager
::
group_manager
(
actor_system
&
sys
)
:
system_
(
sys
)
{
group_manager
::
group_manager
(
actor_system
&
sys
)
:
system_
(
&
sys
)
{
// nop
// nop
}
}
group
group_manager
::
anonymous
()
const
{
group
group_manager
::
anonymous
()
{
CAF_LOG_TRACE
(
""
);
CAF_LOG_TRACE
(
""
);
std
::
string
id
=
"__#"
;
std
::
string
id
=
"__#"
;
id
+=
std
::
to_string
(
++
s_ad_hoc_id
);
id
+=
std
::
to_string
(
++
ad_hoc_id_
);
// local module is guaranteed to not return an error
return
get_local
(
id
);
return
*
get_module
(
"local"
)
->
get
(
id
);
}
}
expected
<
group
>
group_manager
::
get
(
std
::
string
group_uri
)
const
{
expected
<
group
>
group_manager
::
get
(
std
::
string
group_uri
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
group_uri
));
CAF_LOG_TRACE
(
CAF_ARG
(
group_uri
));
// URI parsing is pretty much a brute-force approach, no actual validation yet
// URI parsing is pretty much a brute-force approach, no actual validation yet
auto
p
=
group_uri
.
find
(
':'
);
auto
p
=
group_uri
.
find
(
':'
);
...
@@ -440,38 +77,27 @@ expected<group> group_manager::get(std::string group_uri) const {
...
@@ -440,38 +77,27 @@ expected<group> group_manager::get(std::string group_uri) const {
}
}
expected
<
group
>
group_manager
::
get
(
const
std
::
string
&
module_name
,
expected
<
group
>
group_manager
::
get
(
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
)
const
{
const
std
::
string
&
group_identifier
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
module_name
)
<<
CAF_ARG
(
group_identifier
));
CAF_LOG_TRACE
(
CAF_ARG
(
module_name
)
<<
CAF_ARG
(
group_identifier
));
if
(
auto
mod
=
get_module
(
module_name
))
if
(
auto
mod
=
get_module
(
module_name
))
return
mod
->
get
(
group_identifier
);
return
mod
->
get
(
group_identifier
);
std
::
string
error_msg
=
R"(no module named ")"
;
std
::
string
error_msg
=
R"__(no module named ")__"
;
error_msg
+=
module_name
;
error_msg
+=
R"(" found)"
;
return
make_error
(
sec
::
no_such_group_module
,
std
::
move
(
error_msg
));
}
expected
<
group
>
group_manager
::
get
(
const
std
::
string
&
module_name
,
const
std
::
string
&
group_identifier
,
const
actor
&
dispatcher
)
const
{
CAF_LOG_TRACE
(
CAF_ARG
(
module_name
)
<<
CAF_ARG
(
group_identifier
));
if
(
auto
mod
=
get_module
(
module_name
))
return
mod
->
get
(
group_identifier
,
dispatcher
);
std
::
string
error_msg
=
R"(no module named ")"
;
error_msg
+=
module_name
;
error_msg
+=
module_name
;
error_msg
+=
R"
(" found)
"
;
error_msg
+=
R"
__(" found)__
"
;
return
make_error
(
sec
::
no_such_group_module
,
std
::
move
(
error_msg
));
return
make_error
(
sec
::
no_such_group_module
,
std
::
move
(
error_msg
));
}
}
optional
<
group_module
&>
group_manager
::
get_module
(
const
std
::
string
&
x
)
const
{
group
group_manager
::
get_local
(
const
std
::
string
&
group_identifier
)
{
auto
i
=
mmap_
.
find
(
x
);
auto
result
=
get
(
"local"
,
group_identifier
);
if
(
i
!=
mmap_
.
end
())
CAF_ASSERT
(
result
);
return
*
(
i
->
second
);
return
std
::
move
(
*
result
);
return
none
;
}
}
group
group_manager
::
get_local
(
const
std
::
string
&
group_identifier
)
const
{
group_module_ptr
group_manager
::
get_module
(
const
std
::
string
&
x
)
const
{
// guaranteed to never return an error
if
(
auto
i
=
mmap_
.
find
(
x
);
i
!=
mmap_
.
end
())
return
*
get
(
"local"
,
group_identifier
);
return
i
->
second
;
else
return
nullptr
;
}
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/group_module.cpp
View file @
cf9a69e3
...
@@ -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/test/detail/local_group_module.cpp
0 → 100644
View file @
cf9a69e3
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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
()
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