如何处理程序版本更新时数据结构的变化?

2024-05-31

我做嵌入式软件,但我想这并不是一个真正的嵌入式问题。我不(由于技术原因不能)使用像 MySQL 这样的数据库,只使用 C 或 C++ 结构。

是否存在关于如何处理这些结构在程序版本之间的布局变化的通用原理?

让我们拿一本地址簿。从程序版本 x 到 x+1,如果:

  • 删除字段(看起来很简单)或添加字段(如果所有人都可以使用一些新的默认值,那么可以)?
  • 字符串变长还是变短? int 从 8 位到 16 位有符号/无符号?
  • 也许我将姓氏/名字组合起来,或者将名字分成两个字段?

这些只是一些简单的例子;我不是在寻找这些问题的答案,而是寻找通用的解决方案。

显然,我需要一些硬编码逻辑来处理每个更改。

如果有人不从版本 x 升级到 x+1,而是等待 x+2 怎么办?我应该尝试合并这些更改,还是只应用 x -> x+ 1,然后应用 x+1 -> x+2?

如果版本 x+1 有错误,我们需要回滚到软件的先前版本,但已经“升级”了数据结构怎么办?

我倾向于TLV(http://en.wikipedia.org/wiki/Type-length-value http://en.wikipedia.org/wiki/Type-length-value)但可以看到很多潜在的令人头痛的问题。

这不是什么新鲜事,所以我只是想知道其他人是如何做到的......


我确实有一些代码,如果需要的话,将较长的字符串与两个较短的段混淆在一起。恶心。以下是我在保持一些数据兼容 12 年后的经验:

定义你的目标- 那里有两个:

  • 新版本应该能够读取旧版本写入的内容
  • 旧版本应该能够读取新版本写入的内容(更难)

添加对版本 0 的版本支持- 至少写一个版本头。再加上保留(可能很多)旧的阅读器代码,可以简单地解决第一种情况。如果您不想实施情况 2,请开始拒绝新数据现在!

如果您只需要情况 1,并且随着时间的推移预期的变化相当小,那么您就已经准备好了。不管怎样,在第一次发布之前做好这两件事可以让你以后免去很多麻烦。

序列化期间转换- 在运行时,仅将数据以“新格式”保存在内存中。在持久性限制下进行必要的转换和测试(读取时转换为最新版本,写入时实现向后兼容性)。这将版本问题隔离在一处,有助于避免难以追踪的错误。

保留一组来自所有版本的测试数据。

存储可用类型的子集- 将实际序列化的数据限制为几种数据类型,例如 int、string、double。在most在这种情况下,额外的存储大小是通过支持这些类型的更改的减少的代码大小来弥补的。 (不过,这并不总是您可以在嵌入式系统上做出的权衡)。

例如不要存储比本机宽度短的整数。 (你might当您需要存储长整型数组时需要这样做)。

添加断路器- 存储一些密钥,允许您故意使旧代码显示一条错误消息,表明此新数据不兼容。您可以使用作为错误消息一部分的字符串 - 那么您的旧版本可能会显示一条它不知道的错误消息 - “您可以使用我们网站上的 ConvertX 工具导入此数据”在本地化版本中并不好应用程序,但仍然比“Ungültiges 格式”.

不要直接序列化结构- 这就是逻辑/物理分离。我们与两种人一起工作,两者都有其优点和缺点。如果没有一些运行时开销,这些都无法实现,这几乎会限制您在嵌入式环境中的选择。无论如何,在持久化期间不要使用固定的数组/字符串长度,这应该已经解决了一半的麻烦。

(A) 适当的序列化机制- 我们使用二进制序列化器,允许在存储时启动一个“块”,它有自己的长度标头。读取时,会跳过额外的数据,并且默认初始化缺失的数据(这大大简化了序列化代码中“读取旧数据”的实现。)块可以嵌套。这就是您在物理方面所需的全部内容,但需要一些糖衣来完成常见任务。

(B) 使用不同的内存表示- 内存中的表示基本上是map<id, record>其中 is 可能是一个整数,并且record可能

  • 空(未存储)
  • 原始类型(字符串、整数、双精度型 - 使用越少就越容易)
  • 原始类型数组
  • 和记录数组

我最初这么写是为了让大家不会问我每个格式兼容性问题,虽然实现有很多缺点(我希望我今天能清楚地认识到这个问题......)它可以解决

查询不存在的值默认情况下将返回默认/零初始化值。当您在访问数据和添加新数据时牢记这一点时,这会很有帮助:想象一下版本 1 会自动计算“foo length”,而在版本 2 中用户可以覆盖该设置。 “计算类型”或“长度”中的零值应表示“自动计算”,并且您已设置完毕。

以下是您可以预期的“变化”场景:

  • 标志(是/否)扩展为枚举(“是/否/自动”)
  • 一个设置分为两个设置(例如,“添加边框”可以分为“在偶数天添加边框”/“在奇数天添加边框”。)
  • 添加设置,覆盖(或更糟糕的是,扩展)现有设置。

为了实现案例 2,您还需要考虑:

  • 任何价值都不得被删除或被另一价值取代。 (但在新格式中,它可能会说“不支持”,并且添加了一个新项目)
  • 枚举可能包含未知值、有效范围的其他变化

唷。那是很多。但它并不像看起来那么复杂。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何处理程序版本更新时数据结构的变化? 的相关文章

  • boost::asio + std::future - 关闭套接字后访问冲突

    我正在编写一个简单的 TCP 客户端来发送和接收单行文本 异步操作由 std future 处理 以便于超时阻塞查询 不幸的是 我的测试应用程序在破坏服务器对象时因访问冲突而崩溃 这是我的代码 TCP客户端 hpp ifndef TCPCL
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 如何访问另一个窗体上的ListView控件

    当单击与 ListView 所在表单不同的表单中的按钮时 我试图填充 ListView 我在 Form1 中创建了一个方法以在 Form2 中使用 并将参数传递给 Form1 中的方法 然后填充 ListView 当我调试时 我得到了传递的
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • 将 Excel 导入到 Datagridview

    我使用此代码打开 Excel 文件并将其保存在 DataGridView 中 string name Items string constr Provider Microsoft Jet OLEDB 4 0 Data Source Dial
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 如何使用 watin 中的 FileUploadDialogHandler 访问文件上传对话框

    我正在使用 IE8 和 watin 并尝试通过我的网页测试上传文件 我不能简单地使用 set 方法设置上传文件 例如 ie FileUpload Find ById someId Set C Desktop image jpg 因为上传文本
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • 如何对 Web Api 操作进行后调用?

    我创建了一个 Web API 操作 如下所示 HttpPost public void Load string siteName string providerName UserDetails userDetails implementat
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • 如何在 C# 中调整图像大小同时保持高质量?

    我从这里找到了一篇关于图像处理的文章 http www switchonthecode com tutorials csharp tutorial image editing saving cropping and resizing htt
  • 线程和 fork()。我该如何处理呢? [复制]

    这个问题在这里已经有答案了 可能的重复 多线程程序中的fork https stackoverflow com questions 1235516 fork in multi threaded program 如果我有一个使用 fork 的
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个

随机推荐