Überblick
Jede DDS-Entity (DomainParticipant, Topic, Publisher/Subscriber, DataWriter/DataReader) trägt einen QoS-Block aus den anwendbaren Policies. Die Policies sind in drei Achsen organisiert:
- RxO-Compatibility — beim Match werden Writer-„offered" und Reader-„requested" verglichen. Mismatch blockt Discovery-Match und triggert
OFFERED_INCOMPATIBLE_QOS/REQUESTED_INCOMPATIBLE_QOS. Betrifft 9 von 22 Policies (siehe Compatibility-Matrix).
- Within-Entity-Konsistenz — gewisse Policies haben Wechselwirkungen innerhalb einer Entity (z.B.
HistoryQos.depth ≤ ResourceLimits.max_samples_per_instance). set_qos() lehnt inkonsistente Sets mit InconsistentPolicy ab.
- Mutability — manche Policies dürfen nach
enable() nicht mehr geändert werden (immutable). Setzen vor dem ersten Sample-Schreiben/-Lesen.
Default-Werte folgen exakt der Spec (DDS 1.4 §2.2.3). Pro Policy-Block unten: Spec-§, Felder, Default, RxO-Verhalten, Mutability und Wenn-nutzen.
Compatibility-Matrix — die 9 RxO-Pairs
Reader „requests" einen Wert, Writer „offers" einen. Diese 9 Policies haben eine RxO-Rule aus DDS 1.4 §2.2.3 — alle anderen 13 Policies haben kein Compatibility-Verhalten.
| Policy | Spec § | Match-Rule (offered vs. requested) | RxO-Enum |
Reliability | §2.2.3.14 | Reliable offered ≥ BestEffort requested. Reader Reliable matched nur Writer Reliable. | IncompatibleReason::Reliability |
Durability | §2.2.3.4 | offered ≥ requested in Volatile < TransientLocal < Transient < Persistent. | IncompatibleReason::Durability |
Deadline | §2.2.3.7 | offered ≤ requested (Writer-Period muss ≤ Reader-Erwartung sein). | IncompatibleReason::Deadline |
LatencyBudget | §2.2.3.8 | offered ≤ requested. Hint-Charakter, aber RxO-relevant. | IncompatibleReason::LatencyBudget |
Liveliness | §2.2.3.11 | offered.kind ≥ requested.kind in Automatic < ManualByParticipant < ManualByTopic, UND offered.lease_duration ≤ requested.lease_duration. | IncompatibleReason::Liveliness |
DestinationOrder | §2.2.3.17 | offered ≥ requested in ByReceptionTimestamp < BySourceTimestamp. | IncompatibleReason::DestinationOrder |
Presentation | §2.2.3.6 | offered.access_scope ≥ requested in Instance < Topic < Group, plus coherent/ordered offered ⊇ requested. | IncompatibleReason::Presentation |
Ownership | §2.2.3.9 | offered.kind == requested.kind (Shared/Exclusive müssen identisch sein). | IncompatibleReason::Ownership |
Partition | §2.2.3.13 | mindestens eine Partition-Sequence muss zwischen Writer und Reader matchen (Glob-Pattern via POSIX-fnmatch). | IncompatibleReason::Partition |
Within-Entity-Konsistenzregeln
Manche Policy-Kombinationen sind innerhalb einer Entity inkonsistent — set_qos() lehnt sie mit InconsistentPolicy ab, bevor sie überhaupt am Wire landen.
| Regel | Spec § | Bedingung |
| History.depth ≤ ResourceLimits.max_samples_per_instance | §2.2.3.18 + §2.2.3.19 | Wenn History=KeepLast(N), darf N nicht max_samples_per_instance übersteigen. |
| History=KeepAll erfordert ResourceLimits.max_samples_per_instance=UNLIMITED | §2.2.3.18 | KeepAll kann ohne UNLIMITED in OutOfResources-State laufen. |
| OwnershipStrength gilt nur wenn Ownership=Exclusive | §2.2.3.10 | Setting Strength bei Ownership=Shared ist No-Op (kein Fehler). |
| LivelinessQos.lease_duration > 0 wenn kind≠Automatic | §2.2.3.11 | ManualByParticipant/Topic mit lease=0 ist degenerated. |
| DurabilityServiceQos.history_depth ≤ DurabilityServiceQos.max_samples_per_instance | §2.2.3.5 | Wie History/ResourceLimits, aber für den Persistence-Service. |
| ResourceLimits.max_samples_per_instance ≤ ResourceLimits.max_samples | §2.2.3.19 | Per-Instance-Cap darf nicht über das Total-Cap. |
Mutability nach enable()
DDS 1.4 §2.2.3 markiert jede Policy als mutable (kann nach enable() via set_qos() geändert werden) oder immutable (nur vor enable() setzbar; danach wirft set_qos() einen ImmutablePolicy-Error).
| Policy | Mutable nach enable? | Grund |
UserData / TopicData / GroupData | ✓ mutable | Opaque Bytes, nur Discovery-Side-Effect. |
Durability | ✗ immutable | Beeinflusst Writer-Cache-Backing — kann nicht im Flug geändert werden. |
DurabilityService | ✗ immutable | Persistence-Service-Konfig. |
Presentation | ✗ immutable | Coherent/ordered-Modus an Topic gebunden. |
Deadline | ✓ mutable | Reine Status-Trigger-Logik. |
LatencyBudget | ✓ mutable | Scheduler-Hint. |
Ownership | ✗ immutable | Bestimmt Instance-Routing. |
OwnershipStrength | ✓ mutable | Dynamisches Strength-Voting. |
Liveliness | ✗ immutable | Lease-Watchdog kann nicht im Flug umgeschaltet werden. |
TimeBasedFilter | ✓ mutable | Reader-Side-Sampling-Filter. |
Partition | ✓ mutable | Dynamische Re-Matching mit anderen Partitionen. |
Reliability | ✗ immutable | Wire-Protokoll-Modus (RTPS Best-Effort vs. Reliable). |
TransportPriority | ✓ mutable | Hint für Transport-Scheduling. |
Lifespan | ✓ mutable | Gilt nur für nachfolgende Samples. |
DestinationOrder | ✗ immutable | Sample-Ordering-Modus. |
History | ✗ immutable | Cache-Backing-Strategie. |
ResourceLimits | ✗ immutable | Cache-Allokation. |
EntityFactory | ✓ mutable | Beeinflusst nur Neu-Erzeugung untergeordneter Entities. |
WriterDataLifecycle | ✓ mutable | Reine Verhaltens-Flag. |
ReaderDataLifecycle | ✓ mutable | Auto-Purge-Timer. |
Data-Payload-Policies (3)
Drei opaque sequence<octet>-Slots, die im Discovery ausgetauscht werden. Keine RxO-Compatibility, kein Match-Effekt — nutzbar für eigene Metadata-Übertragung am Discovery-Kanal.
1 · UserDataQosPolicy §2.2.3.1 · auf Participant/DataReader/DataWriter
Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Application-spezifische Metadata, die der Discovery-Layer transportiert (Custom-Auth-Tokens, Build-Version, Deployment-Identifier). Aufpassen bei DDS-Security — der Inhalt ist sichtbar für jeden, der Discovery sehen darf.
Repo: crates/qos/src/policies/generic_data.rs (gemeinsam mit TopicData + GroupData)
2 · TopicDataQosPolicy §2.2.3.2 · auf Topic
Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Topic-spezifische Metadata (z.B. Schema-Hash, OEM-Topic-ID). Wird mit dem Topic-Discovery-Eintrag propagiert.
Repo: crates/qos/src/policies/generic_data.rs
3 · GroupDataQosPolicy §2.2.3.3 · auf Publisher/Subscriber
Felder: value: Vec<u8> · Default: empty · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Group-Level-Metadata bei Coherent/Ordered Sets — z.B. Transaktions-ID einer kohärenten Sample-Gruppe.
Repo: crates/qos/src/policies/generic_data.rs
Durability-Policies (2)
Bestimmt, ob und wie Samples für Late-Joiner verfügbar bleiben.
4 · DurabilityQosPolicy §2.2.3.4 · auf Topic/DataReader/DataWriter
Felder: kind: DurabilityKind (Volatile · TransientLocal · Transient · Persistent) · Default: Volatile · RxO: offered ≥ requested · Mutable: ✗ nein
Wenn nutzen: Volatile für Telemetry (Verlust OK). TransientLocal für State-Topics (Setpoints, Mode), damit Late-Joiner den letzten Wert sehen. Transient/Persistent liefert der eingebaute DurabilityService: Transient hält die History in-memory, Persistent on-disk (übersteht einen Neustart) — Late-Joiner-Replay ist für beide Stufen end-to-end getestet. Cross-Vendor-Replay von Transient/Persistent ist eine OMG-Spec-Lücke (RTPS spezifiziert dafür keine Wire-Mechanik), heute also ZeroDDS↔ZeroDDS.
Repo: crates/qos/src/policies/durability.rs
5 · DurabilityServiceQosPolicy §2.2.3.5 · auf Topic/DataWriter
Felder: service_cleanup_delay: Duration · history_kind: HistoryKind · history_depth: i32 · max_samples / max_instances / max_samples_per_instance: i32 · Default: KeepLast(1) + UNLIMITED · RxO: kein · Mutable: ✗ nein
Wenn nutzen: Konfiguriert den Persistence-Service hinter Transient/Persistent Durability. Wird nur ausgewertet, wenn Durability=Transient/Persistent gesetzt ist.
Repo: crates/qos/src/policies/durability_service.rs
Liveliness & Health (2)
Failure-Detection: Reader will wissen, ob Writer noch "lebt". Deadline ist die Sample-Frequenz-Garantie.
6 · LivelinessQosPolicy §2.2.3.11 · auf Topic/DataReader/DataWriter
Felder: kind: LivelinessKind (Automatic · ManualByParticipant · ManualByTopic) · lease_duration: Duration · Default: Automatic/INFINITE · RxO: offered.kind ≥ requested.kind UND offered.lease ≤ requested.lease · Mutable: ✗ nein
Wenn nutzen: Automatic für Telemetry (DDS-Stack pingt selbst). ManualByParticipant wenn die App durch assert_liveliness() oder regelmäßiges write() Liveness signalisieren will (Heartbeat-Modell). ManualByTopic für Failover-Patterns (siehe Cookbook §3).
Repo: crates/qos/src/policies/liveliness.rs
7 · DeadlineQosPolicy §2.2.3.7 · auf Topic/DataReader/DataWriter
Felder: period: Duration · Default: INFINITE · RxO: offered ≤ requested · Mutable: ✓ ja
Wenn nutzen: Control-Loops mit Frequenz-Garantie. Writer-Deadline-Miss triggert OfferedDeadlineMissedStatus, Reader-Side RequestedDeadlineMissedStatus. Listener-Callback (siehe DCPS) reagiert auf Misses.
Repo: crates/qos/src/policies/deadline.rs
Reliability & Order (3)
Wire-Garantien: ob Samples ankommen müssen, in welcher Reihenfolge sie auf der Reader-Side liegen.
8 · ReliabilityQosPolicy §2.2.3.14 · auf Topic/DataReader/DataWriter
Felder: kind: ReliabilityKind (BestEffort · Reliable) · max_blocking_time: Duration · Default: Writer Reliable, Reader BestEffort · RxO: offered ≥ requested · Mutable: ✗ nein
Wenn nutzen: BestEffort für Telemetry (kein ACK, kein Retransmit). Reliable für Commands, State-Updates, Config-Topics — ACK/NACK über RTPS, Retransmit auf Daten-Loss. max_blocking_time ist die Wartezeit auf write() bei vollem Cache.
Repo: crates/qos/src/policies/reliability.rs
9 · DestinationOrderQosPolicy §2.2.3.17 · auf Topic/DataReader/DataWriter
Felder: kind: DestinationOrderKind (ByReceptionTimestamp · BySourceTimestamp) · Default: ByReceptionTimestamp · RxO: offered ≥ requested · Mutable: ✗ nein
Wenn nutzen: ByReceptionTimestamp ist der Default — Sample-Order ergibt sich aus Reader-Ankunft. BySourceTimestamp wenn Writer-seitige Zeitstempel logisch korrekt sind (Clock-synced Cluster, Replay-Szenarien).
Repo: crates/qos/src/policies/destination_order.rs
10 · LatencyBudgetQosPolicy §2.2.3.8 · auf Topic/DataReader/DataWriter
Felder: duration: Duration · Default: 0 ns · RxO: offered ≤ requested · Mutable: ✓ ja
Wenn nutzen: Hint für den Transport-Scheduler — wieviel Zeit der Sample-Pfad maximal nutzen darf. Kein direkter Wire-Effekt; eher Optimierungs-Indikator (Batching, Priorisierung).
Repo: crates/qos/src/policies/latency_budget.rs
Ownership (2)
Wer darf schreiben? Bei Exclusive: nur der stärkste Writer ist aktiv.
11 · OwnershipQosPolicy §2.2.3.9 · auf Topic/DataReader/DataWriter
Felder: kind: OwnershipKind (Shared · Exclusive) · Default: Shared · RxO: offered.kind == requested.kind · Mutable: ✗ nein
Wenn nutzen: Shared erlaubt mehrere Writer pro Instance (Standard). Exclusive für Hot-Standby-Failover — nur der Writer mit höchster OwnershipStrength ist aktiv (siehe Cookbook §3).
Repo: crates/qos/src/policies/ownership.rs
12 · OwnershipStrengthQosPolicy §2.2.3.10 · auf DataWriter
Felder: value: i32 · Default: 0 · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Strength-Voting bei Ownership=Exclusive. Höchster Wert gewinnt. Mutable-Setter erlaubt dynamische Re-Election (Heartbeat-basiertes Promote/Demote).
Repo: crates/qos/src/policies/ownership_strength.rs
History & Resources (2)
Wie viele Samples werden im Writer/Reader-Cache gehalten?
13 · HistoryQosPolicy §2.2.3.18 · auf Topic/DataReader/DataWriter
Felder: kind: HistoryKind (KeepLast · KeepAll) · depth: i32 · Default: KeepLast(1) · RxO: kein · Mutable: ✗ nein
Wenn nutzen: KeepLast(N) für Sliding-Window (älteste werden überschrieben). KeepAll für Audit-Log-Pattern — alles bis ResourceLimits halten. Bei KeepAll + Reliable: Writer blockt bei vollem Cache (siehe Reliability.max_blocking_time).
Repo: crates/qos/src/policies/history.rs
14 · ResourceLimitsQosPolicy §2.2.3.19 · auf Topic/DataReader/DataWriter
Felder: max_samples: i32 · max_instances: i32 · max_samples_per_instance: i32 (UNLIMITED = -1) · Default: 1000 / 10 / 100 · RxO: kein · Mutable: ✗ nein
Wenn nutzen: Hard-Cap auf Cache-Allokation. Bei Reliable + KeepAll erreicht das Cache-Limit, blockt Writer (OutOfResources). Setze passend zur erwarteten Daten-Rate und Reader-Verzögerung.
Repo: crates/qos/src/policies/resource_limits.rs
Presentation (1)
15 · PresentationQosPolicy §2.2.3.6 · auf Publisher/Subscriber
Felder: access_scope: PresentationAccessScope (Instance · Topic · Group) · coherent_access: bool · ordered_access: bool · Default: Instance/false/false · RxO: offered.scope ≥ requested.scope, coherent/ordered offered ⊇ requested · Mutable: ✗ nein
Wenn nutzen: Coherent-Sets gruppieren Samples zu einer atomar-sichtbaren Einheit (alle oder keine). Ordered-Sets garantieren Sample-Order über mehrere Topics einer Group (Multi-Topic-Transaktion). Höhere Scopes (Topic, Group) sind teurer und erfordern Coordination-Overhead.
Repo: crates/qos/src/policies/presentation.rs
Partition (1)
16 · PartitionQosPolicy §2.2.3.13 · auf Publisher/Subscriber
Felder: names: Vec<String> (POSIX-fnmatch-Glob-Pattern erlaubt) · Default: [""] (Default-Partition) · RxO: mindestens eine Partition muss zwischen Writer und Reader matchen · Mutable: ✓ ja
Wenn nutzen: Logische Mandantentrennung im selben Domain (z.B. customer-A/odom vs. customer-B/odom). Glob-Pattern wie customer-* erlauben dynamisches Subscriber-Matching ohne Topic-Umkonfiguration. Wichtig: Partition ist Match-Filter, kein Network-Isolation — Discovery sieht trotzdem alle.
Repo: crates/qos/src/policies/partition.rs
Filter & Lifespan (2)
Reader-seitige Sample-Filter (Time-Based) und Writer-seitige Sample-Verfallszeit.
17 · TimeBasedFilterQosPolicy §2.2.3.12 · auf DataReader
Felder: minimum_separation: Duration · Default: 0 ns · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Reader-Side-Downsampling. Mindest-Abstand zwischen empfangenen Samples derselben Instance. Spart Reader-Verarbeitungs-CPU bei Hochfrequenz-Topics, wenn der Konsument nur eine Subset-Rate braucht.
Repo: crates/qos/src/policies/time_based_filter.rs
18 · LifespanQosPolicy §2.2.3.16 · auf Topic/DataWriter
Felder: duration: Duration · Default: INFINITE · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Samples, die älter als duration sind, werden automatisch aus dem Cache entfernt (Writer-Seite und Reader-Seite, wenn TransientLocal). Nützlich für State-Topics mit "stale data is bad data"-Semantik (z.B. Setpoint > 30s alt = ignorieren).
Repo: crates/qos/src/policies/lifespan.rs
Entity & Lifecycle (3)
Auto-Enable-Verhalten und Instance-Lifecycle-Reaktionen.
19 · EntityFactoryQosPolicy §2.2.3.20 · auf Participant/Publisher/Subscriber/DomainParticipantFactory
Felder: autoenable_created_entities: bool · Default: true · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Wenn true, werden neu erzeugte Sub-Entities sofort enable'd. Wenn false, muss der Anwender manuell enable() rufen — nützlich um QoS-Sets vor dem ersten Discovery-Beacon zu finalisieren.
Repo: crates/qos/src/policies/entity_factory.rs
20 · WriterDataLifecycleQosPolicy §2.2.3.21 · auf DataWriter
Felder: autodispose_unregistered_instances: bool · Default: true · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Wenn true, wird unregister_instance() implizit als dispose() behandelt (Reader sieht NOT_ALIVE_DISPOSED). Wenn false, nur NOT_ALIVE_NO_WRITERS ohne Dispose-Marker.
Repo: crates/qos/src/policies/data_lifecycle.rs
21 · ReaderDataLifecycleQosPolicy §2.2.3.22 · auf DataReader
Felder: autopurge_nowriter_samples_delay: Duration · autopurge_disposed_samples_delay: Duration · Default: INFINITE / INFINITE · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Reader-seitige Auto-Purge-Timer für ungenutzte/disposed Samples. Verhindert, dass der Reader-Cache mit alten/toten Instances vollläuft. Standard-INFINITE = nie auto-purge.
Repo: crates/qos/src/policies/data_lifecycle.rs
Transport (1)
22 · TransportPriorityQosPolicy §2.2.3.15 · auf Topic/DataWriter
Felder: value: i32 · Default: 0 · RxO: kein · Mutable: ✓ ja
Wenn nutzen: Hint für den Transport-Layer-Scheduler (z.B. UDP DSCP-Tag, TSN-Stream-Priorität). Implementierungs-spezifisch — Wert ohne Wire-Garantie. Wichtig in Mixed-Critical-Setups (Control + Telemetry auf gleichem Link).
Repo: crates/qos/src/policies/transport_priority.rs · Auswertung im Transport-Layer: zerodds-transport