Skip to content

Commit 085e8b6

Browse files
author
Graham Palmer
committed
Remove explicit segment requesting ability from subscribers and separate runtime mapping request from initialization
1 parent 1e8a562 commit 085e8b6

File tree

1 file changed

+52
-61
lines changed

1 file changed

+52
-61
lines changed

doc/design/draft/named-segments.md

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,45 @@ name instead of by access control. This will increase flexibility while still gr
4444

4545
* The RouDi configuration must support specifying names for shared memory segments.
4646
* If a name is not configured, the fallback behavior must be the same as it is currently - assigning the name of the current process user.
47-
* Communication endpoints should be able to specify which segments they intend to use.
47+
* Producers should be able to specify which segments they intend to use.
4848
* Publishers may specify a single segment into which they will publish.
49-
* Subscribers may specify one or more segments from which they may receive messages.
50-
* Clients and Servers may specify a single segment into which they send requests/responses, and multiple segments from which they receive responses/requests.
49+
* Clients and Servers may specify a single segment into which they send requests and responses, respectively.
5150
* When no segment is specified, the fallback behavior must be the same as it is currently
5251
* Publishers will select the *unique* segment they have write access to.
53-
* Subscribers will receive messages from all segments they have read access to.
54-
* Clients and Servers follow the same rules as Publishers for data they send and the same rules as Subscribers for data they receive.
55-
* Creation will fail if a communication endpoint requests to use a segment to which it does not
56-
have the proper access rights.
52+
* Clients and Servers will select the *unique* segment they have write access to, for publishing requests and responses, respectively.
53+
* Creation will fail if a producer requests to use a segment to which it does not have write access.
5754

5855
### Optional additional requirements
5956

60-
* When initializing the runtime, a list of segment names may be provided. In this case, rather than mapping all shared memory segments available in the system, only those that are named shall be mapped.
61-
* When a communication endpoint requests a segment that has not been mapped, this may be configured to either result in a failure or in mapping the requested segment on the fly.
57+
* When initializing the runtime, the user may specify via an enum whether they wish to map
58+
* All segments to which the current process has read access
59+
* All segments to which the current process has write access
60+
* All segments to which the current process has either read or write access (deprecated-default)
61+
* No segments (future default)
62+
* The user may additionally map specific segments after initialization by calling
63+
* `mapSegmentForReading(name)`
64+
* This will check for existence of the specified segment and map it as long as user has read access to it
65+
* An informative error will be returned under the following circumstances
66+
* The segment has already been mapped
67+
* The segment does not exist
68+
* The segment exists but the current process does not have read access to it
69+
* `mapSegmentForWriting(name)`
70+
* This will check for the existence of the specified segment and map it as long as the user has write access to it
71+
* An informative error will be returned under the following circumstances
72+
* The segment has already been mapped
73+
* The segment does not exist
74+
* The segment exists but the current process does not have write access to it
75+
* When the user attempts to create a producer that requests a segment which is not mapped, this will trigger the error handler and cause program termination.
76+
* In the future if we expose a builder-pattern method of creating producers, we could instead have the builder return an error indicating the segment is not mapped.
77+
* An alternative to the above is to add an additional enum with configuration options allowing for the runtime to map requested segments on the fly. This increases flexibility, but because it is already possible to tell the runtime to map a specific segment, this would not add much value. A user who wishes to ensure a producer's segment is already mapped may simply call `mapSegmentForWriting(name)`, ignoring the error indicating that the segment has already been mapped.
78+
* When a consumer is created, an error will only occur if **no** segment has been mapped. Otherwise if a producer on the same channel as the consumer uses a segment the consumer does not have access to (whether because the segment is unmapped or because the consumer does not have read access), this will result in a fatal error.
79+
* Improvements could be made to the RouDi logic determining if producers and consumers are compatible - to check if the consumer has access to the segment the producer writes to. This is however considered out of scope for the current design proposal.
6280

6381
## Design
6482

6583
### Updated RouDi Config
6684

67-
Supporting named segments will require add an additional `name` field to the RouDi config under the `[[segment]]` heading, as well as updating the config version Example:
85+
Supporting named segments will require adding an additional `name` field to the RouDi config under the `[[segment]]` heading, as well as updating the config version Example:
6886

6987
```
7088
[general]
@@ -93,38 +111,21 @@ struct PublisherOptions
93111
ShmName_t segmentName{""};
94112
```
95113

96-
#### When creating a Subscriber
97-
98-
A similar field will be added to the [SubscriberOptions struct](../../../iceoryx_posh/include/iceoryx_posh/popo/subscriber_options.hpp), except that it will support multiple elements
99-
100-
```
101-
struct SubscriberOptions
102-
{
103-
...
104-
vector<ShmName_t, MAX_SUBSCRIBER_SEGMENTS> segmentNames{};
105-
```
106-
107-
`MAX_SUBSCRIBER_SEGMENTS` can be set to some reasonably small value to start with since explicitly allowing many but not all read-access segments is an unlikely use case.
108-
109-
If this assumption turns out to be wrong however, we can always update it to be `MAX_SHM_SEGMENTS` instead.
110-
111114
#### When creating Clients and Servers
112115

113-
Clients and Servers will have similar fields, distinguished by request/response:
116+
Clients and Servers will have similar fields as publishers for the messages which they produce:
114117

115118
```
116119
struct ClientOptions
117120
{
118121
...
119122
ShmName_t requestSegmentName{""};
120-
vector<ShmName_t, MAX_RESPONSE_SEGMENTS> responseSegmentNames{};
121123
```
122124

123125
```
124126
struct ServerOptions
125127
{
126128
...
127-
vector<ShmName_t, MAX_REQUEST_SEGMENTS> requestSegmentNames{};
128129
ShmName_t responseSegmentName{""};
129130
```
130131

@@ -141,23 +142,26 @@ Tying this together with requesting segments, this could look something like:
141142
class DefaultRuntimeBuilder
142143
{
143144
...
144-
IOX_BUILDER_PARAMETER(vector<ShmName_t>, shmSegmentNames, {});
145-
IOX_BUILDER_PARAMETER(bool, allowUnmappedSegments, false);
145+
IOX_BUILDER_PARAMETER(MappedSegments, premappedSegments, MappedSegments::ReadAndWrite)
146+
IOX_BUILDER_PARAMETER(vector<ShmName_t, MAX_SHM_SEGMENTS>, shmSegmentNames, {});
147+
IOX_BUILDER_PARAMETER(UnmappedSegmentBehavior, unmappedSegmentBehavior, UnmappedSegmentBehavior::LoadOnDemand);
146148
...
147149
public:
148150
expected<DefaultRuntime, RuntimeBuilderError> create() noexcept;
149151
```
150152

151-
The `create` method of this builder would then return a custom error if a
152-
segment was requested that either does not exist or the current process does not have access to.
153+
The `create` method of this builder would then return a custom error if:
154+
* A segment is requested which does not exist
155+
* A segment is requested which the current process does not have access to
156+
* A segment is requested which has already been captured by the `premappedSegments` option
153157

154-
Additionally, when a publisher or subscriber is created, the `allowUnmappedSegments` would determine whether or not we fail or try to map the newly requested segment on the fly.
158+
Additionally, when a producer is created, the `unamppedSegmentBehavior` option would determine whether or not we fail or try to map the newly requested segment on the fly.
155159

156160
### Segment Matching Algorithm
157161

158162
Ensuring backwards compatibility means carefully crafting how we register segments. The following pseudocode demonstrates how this should work in different scenarios
159163

160-
#### Endpoints requesting write access (Publisher, Client Request, Server Response)
164+
#### Producers requesting write access (Publisher, Client Request, Server Response)
161165

162166
In RouDi, given:
163167
* `userGroups` - A list of POSIX user groups a publishing process belongs to called
@@ -177,48 +181,35 @@ In RouDi, given:
177181
4. At the end of iteration, if a matching segment has been found, return the segment information
178182
5. Otherwise return an error indicating that no matching segment has been found
179183

180-
#### Endpoints requesting read access (Subscriber, Client Response, Server Request)
181-
182-
In RouDi, when handling a port request for a new subscriber (and WLOG for clients and servers), given:
183-
* PublisherOptions for a single publisher publishing on the requested topic
184-
* SubscriberOptions for the requested subscriber
185-
186-
We determine if the endpoints are compatible as follows (and we repeat this for each publisher if there are several):
187-
1. To determine if the subscriber and publisher segments match:
188-
1. If the list of segment names provided by the subscriber is non-empty, check if any name matches the name provided by the publisher (an empty name is a non-match)
189-
2. If the list of segment names provided by the subscriber is empty, then it is always a match
190-
2. Determine if blocking policies are compatible
191-
3. Determine if history request is compatible
192-
4. Return true if all cases are met
193-
194-
If no publisher is compatible with a subscriber, then RouDi will refuse to provide a port, as is the current behavior when subscribers have incompatible blocking policies.
195-
196184
#### Runtime requesting segments to map
197185

198186
In the client process, while initializing the runtime, given:
199187
* `userGroups` - A list of POSIX user groups a publishing process belongs to called
200-
* `segmentContainer` - A list of shared memory segment information
188+
* `segmentContainer` - A list of shared memory segment information
189+
* `premappedSegments` - An enum indicating which group of segments should be mapped by default
201190
* `segmentFilter` - A (possibly empty) list of segment names to filter against
202191

203192
In order to determine which segments to map:
204193

205-
1. If `segmentFilter` is empty then
206-
1. Determine which segments the process has access rights (read or write) to.
207-
2. Map all of them.
194+
1. Map segments according to the `premappedSegments` option
195+
1. If read access segments are requested, map every segment the user has read access to, but not write access
196+
2. If write access segments are requested, map every segment the user has write access to
197+
3. If read and write access segmeents are requested, map every segment the user has either read or write access to
198+
4. If no segments are requested, do nothing
208199
2. If `segmentFilter` is not empty
209200
1. Iterate over each name in the filter
210201
2. If there is a segment that matches the name in the filter
211-
1. If the process has access rights to that segment, map it
212-
2. If not, return an error indicating that a segment was requested the runtime does not have access to.
202+
1. If the segment has already been mapped, return an error indicating that a segment has been requested twice. The error should contain access permissions and the value of the `premappedSegments` option the user understands why it has already been mapped.
203+
2. Otherwise, if the process has access rights to that segment, map it
204+
2. If the process does not have access rights, return an error indicating that a segment was requested the runtime does not have access to.
213205
3. If there is no segment that matches the name in the filter, return an error indicating that there is no segment matching the one requested to be mapped.
214206

215207
## Development Roadmap
216208

217-
- [ ] Extend the RouDi config to support specifying segment names
218-
- [ ] Add the name to the `MePooSegment` data structure and populate it based on the RouDi config
219-
- [ ] Update communication endpoint options structs to include segment names
220-
- [ ] Update the publisher, client request, and server response segment selection logic to take the segment name into account
221-
- [ ] Update the subscriber, client response, and server request compatibility check to check for a segment name match
209+
- [ ] Extend the RouDi config to support specifying segment names to be added to the `SegmentConfig`
210+
- [ ] Add the name to the `MePooSegment` data structure and allow multiple write-access segments to be mapped.
211+
- [ ] Update producer options structs to include segment names
212+
- [ ] Update producer segment selection logic to take the segment name into account
222213

223214
### Optional
224215

0 commit comments

Comments
 (0)