7 Fast DDS-持久化服务

7 Fast DDS-持久化服务

  • [7.1 配置方法](#7.1 配置方法)
  • [7.2 PERSISTENCE:SQLITE3 内置插件](#7.2 PERSISTENCE:SQLITE3 内置插件)
  • [7.3 示例](#7.3 示例)

使用默认 QoS 时,DataWriter 的历史记录仅在 DataWriter 的整个生命周期内对 DataReader 可用。这意味着历史记录不会在 DataWriter 的多次初始化之间持久化,因此在 DataWriter 创建时它处于空状态。类似地,DataReader 的历史记录不会在 DataReader 的生命周期之外持久化,因此在 DataReader 创建时也是空的。然而,eProsima Fast DDS 提供了将 DataWriter 的历史记录存储在持久化数据库中的可能性,以便 DataWriter 可以在创建时从该数据库加载其历史记录。此外,DataReader 可以配置为将最后一个通知的更改存储在数据库中,以便它们在创建时可以恢复其状态。

这种机制允许在启动数据分发服务时恢复先前的状态,从而在例如意外关闭的情况下增加应用程序的鲁棒性。通过配置持久化服务,DataWriter 和 DataReader 可以从关闭发生时它们所处的状态恢复操作。

Note

请注意,DataReader 不会将其整个历史记录存储到数据库中,而是存储来自 DataWriter 的最后一个被通知的变更。这意味着它们将从停止的地方恢复操作,但它们不会拥有之前的信息,因为这些信息已经通知给了应用程序。

Note

可能需要将 DataWriter 和 DataReader 的历史记录深度配置为一个足够大的值,以保证存储在数据库中的所有变更足以让应用程序正确恢复。

Note

需要 RELIABLE_RELIABILITY_QOS 可靠性才能允许完全恢复,因为它保证所有变更都存储在数据库中,并且它们将在重启后对 DataWriter/DataReader 可用。

7.1 配置方法

持久化服务的配置通过设置适当的 DataWriter 和 DataReader 的 DurabilityQosPolicy,以及为每个实体(DomainParticipant、DataWriter 或 DataReader)的 PropertyPolicyQos 指定合适的属性来完成。

  • 要使持久化服务生效,DurabilityQosPolicyKind 需要设置为 TRANSIENT_DURABILITY_QOSPERSISTENT_DURABILITY_QOS
  • 必须使用属性 dds.persistence.guid 在端点(DataWriter 或 DataReader)上设置一个持久化标识符(Guid_t)。此标识符用于从数据库加载相应的数据,并在重启之间同步 DataWriter 和 DataReader。GUID 由 16 个字节组成,分为两组:
    • 前 12 个字节对应于 GuidPrefix_t
    • 最后 4 个字节对应于 EntityId_t
      持久化标识符使用一个由 12 个点分隔的字节组成的字符串来指定,以十六进制表示,后跟一个竖线分隔符(|)以及另外 4 个点分隔的字节,也以十六进制表示(参见示例)。为 DataReader 和 DataWriter 选择合适的 GUID,请参阅 RTPS 标准(第 9.3.1 节《全局唯一标识符(GUID)》)。
      此属性必须在端点级别定义。如果不存在,无论任何插件配置如何,持久性行为都将回退到 TRANSIENT_LOCAL_DURABILITY_QOS
  • 必须使用属性 dds.persistence.plugin 配置一个用于管理数据库的持久化插件(参见《PERSISTENCE:SQLITE3 内置插件》):

7.2 PERSISTENCE:SQLITE3 内置插件

此插件通过使用 SQLite3 API 的本地数据库文件提供持久化功能。要激活该插件,必须将 dds.persistence.plugin 属性添加到 DataWriter 或 DataReader 的 PropertyPolicyQos 中,其值为 builtin.SQLITE3。可选地,可以将 dds.persistence.sqlite3.filename 属性添加到实体的 PropertyPolicyQos 中以指定数据库文件名;如果省略,则使用默认值 persistence.db。这些属性总结如下表:

复制代码
                       Persistence::SQLITE3 配置属性
属性名称 属性值
dds.persistence.plugin builtin.SQLITE3
dds.persistence.sqlite3.filename 用于持久化存储的文件名。默认值:persistence.db

Note

为避免因并发访问 SQLite3 数据库而导致意外延迟,强烈建议为每个 DataWriter 和 DataReader 指定不同的数据库文件。

Important

dds.persistence.plugindds.persistence.sqlite3.filename 是作为一对来解析的:如果在端点(DataWriter/DataReader)级别未设置 dds.persistence.plugin,则这两个属性都将从 DomainParticipant 获取;在端点级别定义了 dds.persistence.sqlite3.filename 但同一级别没有 dds.persistence.plugin,则会被忽略。dds.persistence.guid 必须在端点级别定义;如果缺失,无论任何插件配置如何,行为都将回退到 TRANSIENT_LOCAL_DURABILITY_QOS。强烈建议直接在端点上设置所有三个属性,以获得可预测的行为。

7.3 示例

此示例展示了如何使用 PERSISTENCE:SQLITE3 内置插件,通过 C++ 和 eProsima Fast DDS XML 配置文件(参见 XML 配置文件)来配置持久化服务。

复制代码
/*
 * In order for this example to be self-contained, all the entities are created programatically, including the data
 * type and type support. This has been done using Fast DDS Dynamic Types API, but it could be substituted with a
 * Fast DDS-Gen generated type support if an IDL file is available. The Dynamic Type created here is the equivalent
 * of the following IDL:
 *
 *     struct persistence_topic_type
 *     {
 *         unsigned long index;
 *         string message;
 *     };
 */

// Configure persistence service plugin for DomainParticipant
DomainParticipantQos pqos;
pqos.properties().properties().emplace_back("dds.persistence.plugin", "builtin.SQLITE3");
pqos.properties().properties().emplace_back("dds.persistence.sqlite3.filename", "part_persistence_service.db");
DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0, pqos);

/********************************************************************************************************
* CREATE TYPE AND TYPE SUPPORT
*********************************************************************************************************
* This part could be replaced if IDL file and Fast DDS-Gen are available.
* The type is created with name "persistence_topic_type"
* Additionally, create a data object and populate it, just to show how to do it
********************************************************************************************************/
// Create a struct builder for a type with name "persistence_topic_type"
const std::string topic_type_name = "persistence_topic_type";

TypeDescriptor::_ref_type struct_type_descriptor {traits<TypeDescriptor>::make_shared()};
struct_type_descriptor->kind(TK_STRUCTURE);
struct_type_descriptor->name(topic_type_name);
DynamicTypeBuilder::_ref_type struct_builder {DynamicTypeBuilderFactory::get_instance()->
                                                      create_type(struct_type_descriptor)};

// The type consists of two members, and index and a message. Add members to the struct.
MemberDescriptor::_ref_type index_member_descriptor {traits<MemberDescriptor>::make_shared()};
index_member_descriptor->name("index");
index_member_descriptor->type(DynamicTypeBuilderFactory::get_instance()->
                get_primitive_type(TK_UINT32));
struct_builder->add_member(index_member_descriptor);

MemberDescriptor::_ref_type message_member_descriptor {traits<MemberDescriptor>::make_shared()};
message_member_descriptor->name("message");
message_member_descriptor->type(DynamicTypeBuilderFactory::get_instance()->
                create_string_type(static_cast<uint32_t>(LENGTH_UNLIMITED))->build());
struct_builder->add_member(message_member_descriptor);

// Build the type
DynamicType::_ref_type struct_type {struct_builder->build()};

// Create type support and register the type
TypeSupport type_support(new DynamicPubSubType(struct_type));
type_support.register_type(participant);

// Create data sample a populate data. This is to be used when calling `writer->write()`
DynamicData::_ref_type dyn_helloworld {DynamicDataFactory::get_instance()->create_data(struct_type)};

dyn_helloworld->set_uint32_value(0, 0);
dyn_helloworld->set_string_value(1, "HelloWorld");
/********************************************************************************************************
* END CREATE TYPE AND TYPE SUPPORT
********************************************************************************************************/

// Create a topic
Topic* topic = participant->create_topic("persistence_topic_name", topic_type_name, TOPIC_QOS_DEFAULT);

// Create a publisher and a subscriber with default QoS
Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr);
Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT, nullptr);

// Configure DataWriter's durability and persistence GUID so it can use the persistence service
DataWriterQos dwqos = DATAWRITER_QOS_DEFAULT;
dwqos.history().kind = KEEP_LAST_HISTORY_QOS;
dwqos.history().depth = 20;
dwqos.reliability().kind = RELIABLE_RELIABILITY_QOS;
dwqos.durability().kind = TRANSIENT_DURABILITY_QOS;
dwqos.properties().properties().emplace_back("dds.persistence.plugin", "builtin.SQLITE3");
dwqos.properties().properties().emplace_back("dds.persistence.guid",
        "77.72.69.74.65.72.5f.71.65.72.73.5f|67.75.69.64");
dwqos.properties().properties().emplace_back("dds.persistence.sqlite3.filename", "dw_persistence_service.db");
DataWriter* writer = publisher->create_datawriter(topic, dwqos);

// Configure DataReaders's durability and persistence GUID so it can use the persistence service
DataReaderQos drqos = DATAREADER_QOS_DEFAULT;
drqos.history().kind = KEEP_LAST_HISTORY_QOS;
drqos.history().depth = 20;
drqos.reliability().kind = RELIABLE_RELIABILITY_QOS;
drqos.durability().kind = TRANSIENT_DURABILITY_QOS;
drqos.properties().properties().emplace_back("dds.persistence.plugin", "builtin.SQLITE3");
drqos.properties().properties().emplace_back("dds.persistence.guid",
        "77.72.69.74.65.72.5f.71.65.72.73.5f|67.75.69.65");
drqos.properties().properties().emplace_back("dds.persistence.sqlite3.filename", "dr_persistence_service.db");
DataReader* reader = subscriber->create_datareader(topic, drqos);

Note

有关如何创建 DomainParticipant、DataReader 和 DataWriter 的说明,请分别参阅《基于配置文件的 DomainParticipant 创建》、《基于配置文件的 DataWriter 创建》和《基于配置文件的 DataReader 创建》。

相关推荐
ever_up9734 分钟前
LangChain基础知识概述1
人工智能·python·langchain
豆豆18 分钟前
AI 建站实战:AI 生成前端页面如何集成自有 CMS 系统
人工智能·cms·网站搭建·网站管理系统·ai建站·建站工具·中小企业建站
cjy00011120 分钟前
2026年9月零基础能听懂国内 FDE 讲师的课吗?
大数据·前端·人工智能·fde
百胜软件@百胜软件35 分钟前
百胜软件SenClaw胜券助手正式发布:AI让数据“开口说话”,随时赋能零售运营
大数据·人工智能·零售
程序员天天困36 分钟前
Claude Fable 5.1 到底怎么样?扒完官方跑分和第三方榜单,说几句实话
人工智能·claude
喜欢睡觉40 分钟前
LangChain 输出解析器:从裸文本到结构化输出
人工智能
工业涂料百问43 分钟前
【市场格局】系列(四)汽车、船舶、风电涂料赛道对比:1400亿工业涂料里,哪个细分最“肥“?
人工智能·汽车
桃西西呀1 小时前
红酒标签上的 87 分是怎么算出来的?我拿 1599 瓶真酒把线性回归和逻辑回归拆开讲
人工智能·机器学习·llm
帅哥的AI自修课1 小时前
你的AI开发还是单打独斗?MetaGPT焊死「多智能体协作」,从角色分工到代码生成一篇打通
人工智能
HZZD_HZZD1 小时前
商业综合体分户计量与能源计费:业态差异、公区分摊与转供电合规
大数据·人工智能·能源