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 创建》。

相关推荐
云边有个稻草人1 小时前
时序智能新范式:TimechoAI 大模型赋能工业时序数据全链路分析
人工智能·apache iotdb·时序大模型·timechoai·企业级时序数据解决方案·工业时序数据分析·时序 ai 赋能
weixin_307779131 小时前
从工具到协作者:AI在后端研发中的流程重构与组织赋能
人工智能·后端·python·算法·自动化
云草桑1 小时前
.NET10+AI 架构师全套实战学习文档(含源码、案例、面试题、项目源码)
人工智能·学习·ai·.net
爱吃生蚝的于勒1 小时前
QT开发第三章——常用控件
linux·服务器·开发语言·前端·javascript·c++·qt
装不满的克莱因瓶1 小时前
循环神经网络及LSTM——从序列建模到长期依赖记忆机制
人工智能·pytorch·python·rnn·深度学习·神经网络·lstm
ai产品老杨1 小时前
突破安防碎片化僵局:基于 Docker 与边缘计算的 AI 视频管理平台异构架构设计(附 GB28181/RTSP 统一接入与源码交付)
人工智能·docker·边缘计算
沉下去,苦磨练!1 小时前
深度学习神经网络的搭建
人工智能·算法
夏天的味道٥1 小时前
Spring-AI 多模型接入实战:本地 deepseek + 阿里云百炼 + 硅基流动
人工智能·spring·阿里云
2601_961963381 小时前
从OCR到NLP:AI技术如何赋能电子合同智能审核与风险预警?
网络·人工智能·安全·金融·智能合约