TDB 数据库是Trivial database的缩写。这个东西不一定听过,但是和它相关的Samba应该玩Linux的人都听过。Samba的一些数据就是用TDB存储的。当然了,我们也可以把它用在我们的嵌入式Linux的小型系统中存储我们的数据。

tdb是用key-value的格式存储数据的。我们可以把一个json格式的数据作为value,再给它起个独一无二的名字作为key。把这样的键值对存储到tdb的数据结构里。tdb用的是hash表的结构对每个key做hash处理然后存储在相应的hash链表上。缺省情况下它的hash链表是131个。如下的信息就是一个简单的tdb的数据概况(tdbtool是tdb的一个工具):

pakydu@SRVECT:~$ tdbtool paky.tdb
tdb> info
Size of file/data: 69632/7577
Header offset/logical size: 0/69632
Number of records: 14
Incompatible hash: no
Active/supported feature flags: 0x00000000/0x00000001
Robust mutexes locking: no
Smallest/average/largest keys: 7/15/24
Smallest/average/largest data: 4/525/1147
Smallest/average/largest padding: 5/88/241
Number of dead records: 0
Smallest/average/largest dead records: 0/0/0
Number of free records: 4
Smallest/average/largest free records: 392/14922/57516
Number of hash chains: 131
Smallest/average/largest hash chains: 0/0/1
Number of uncoalesced records: 1
Smallest/average/largest uncoalesced runs: 1/1/1
Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: 0/11/2/86/0/1/1
tdb>  keys
key 7 bytes: VERSION
key 16 bytes: G_Energy Manager
key 9 bytes: G_default
key 13 bytes: I_users_index
key 13 bytes: I_roles_index
key 22 bytes: U_default.tmpl_profile
key 14 bytes: U_user_profile
key 12 bytes: G_Technician
key 16 bytes: U_user_basicinfo
key 14 bytes: G_System Admin
key 18 bytes: U_oneday_basicinfo
key 24 bytes: G_Non-Technical End User
key 24 bytes: U_system.default_profile
key 18 bytes: G_Monitoring Stafftdb> show I_users_index        key 13 bytes
I_users_index
data 11 bytes
[000] 7B 22 75 73 65 72 22 3A  31 7D 00                 {"user": 1}
tdb> show U_user_basicinfokey 16 bytes
U_user_basicinfo
data 302 bytes
[000] 7B 22 75 73 65 72 6E 61  6D 65 22 3A 22 75 73 65  {"userna me":"use
[010] 72 22 2C 22 70 61 73 73  77 6F 72 64 22 3A 22 31  r","pass word":"1
[020] 61 31 64 63 39 31 63 39  30 37 33 32 35 63 36 39  a1dc91c9 07325c69
[030] 32 37 31 64 64 66 30 63  39 34 34 62 63 37 32 22  271ddf0c 944bc72"
[040] 2C 22 66 75 6C 6C 6E 61  6D 65 22 3A 22 44 65 66  ,"fullna me":"Def
[050] 61 75 6C 74 20 55 73 65  72 22 2C 22 64 65 73 63  ault Use r","desc
[060] 72 69 70 74 69 6F 6E 22  3A 22 54 68 65 20 66 69  ription" :"The fi
[070] 72 73 74 20 64 65 66 61  75 6C 74 20 75 73 65 72  rst defa ult user
[080] 22 2C 22 65 6D 61 69 6C  22 3A 22 75 73 65 72 40  ","email ":"user@
[090] 65 6D 65 72 73 6F 6E 2E  63 6F 6D 22 2C 22 6F 66  emerson. com","of
[0A0] 66 69 63 65 70 68 6F 6E  65 22 3A 22 34 30 34 2D  ficephon e":"404-
[0B0] 35 35 35 2D 30 31 31 31  22 2C 22 73 6D 73 22 3A  555-0111 ","sms":
[0C0] 22 34 30 34 2D 35 35 35  2D 30 31 37 37 22 2C 22  "404-555 -0177","
[0D0] 6C 6F 63 61 6C 65 22 3A  22 65 6E 2D 55 53 22 2C  locale": "en-US",
[0E0] 22 74 65 61 6D 22 3A 22  22 2C 22 72 6F 6C 65 73  "team":" ","roles
[0F0] 22 3A 5B 22 53 79 73 74  65 6D 20 41 64 6D 69 6E  ":["Syst em Admin
[100] 22 5D 2C 22 61 6C 61 72  6D 6F 75 74 70 75 74 6F  "],"alar moutputo
[110] 6E 6C 79 22 3A 22 66 61  6C 73 65 22 2C 22 64 69  nly":"fa lse","di
[120] 73 63 69 70 6C 69 6E 65  22 3A 5B 5D 7D 00        scipline ":[]}
tdb> 

对这个tdb的数据库结构有了一个大概的了解后,我们可以根据自己的应用去确定是否使用到自己的产品中。如果你决定要使用它了,那就要开始下载它的源代码,交叉编译,测试。

  1. 下载代码:https://www.samba.org/ftp/tdb/

你可以根据下载任意版本使用,关于不同的版本的编译,我是用过1.2,1.3.1 和1.3.11的,不同的版本的交叉编译会有所不同。下面会详细介绍编译的情况。个人不是很推荐使用最新的版本。

2. 交叉编译代码:我的项目多半是arm的平台。所以我的介绍主要是针对arm平台。

  • 编译工具链:这个可以根据项目,使用通用的arm-linux-gnueabihf-gcc,或者芯片厂商提供的。
  • 交叉编译:
version 1.2 version 1.3.1 version 1.3.11

./configure  CC=arm-linux-gnueabihf-gcc \

--host=arm-linux

Note:

这个版本使用的是比较通用的configure方式,具体的可以使用

./configure --help 获得更多的参数设置帮助

CC=arm-linux-gnueabihf-gcc  ./configure -C --prefix=${D}/usr/ --cross-compile \

--cross-answers=answers.txt

CC=arm-linux-gnueabihf-gcc ./configure --cross-compile --cross-execute='qemu-arm-static -L /usr/arm-linux-gnueabihf'

version 1.2的方式很多开源软件都是用的这种方式,这里不做过多介绍。主要对1.3.1和1.3.11介绍一下,这两个版本主要是用的waf的方式:https://wiki.samba.org/index.php/Waf

Note:在这里在强调一个东西: 比较新的libtdb使用的是waf,这个是要依赖pythone的,这个要保证你使用的代码别的版本和你的电脑上python的版本匹配。

cross-compiling
You can build for non-host architectures by using the cross-compilation features of the build.There are two approaches to cross compiling with the waf build:using a --cross-execute emulator
using a --cross-answers file
In either case you will need a cross-compiler setup installed.Using --cross-execute
If you have an emulator setup to run cross-compiled binaries then you can use --cross-execute. This will allow you to accurately configure your build with the correct answers.For example, on a Debian derived system for an ARM target you would install gcc-4.3-arm-linux-gnu, linux-kernel-headers-arm-cross and qemu-arm-static. That will give you enough to create ARM binaries.You may find the following apt sources useful for this:deb http://mirror.csclub.uwaterloo.ca/emdebian/ stable main
deb-src http://mirror.csclub.uwaterloo.ca/emdebian/ stable main
With those installed, you would then configure like this:CC=arm-linux-gnu-gcc waf configure --cross-compile --cross-execute='qemu-arm-static -L /usr/arm-linux-gnu'
that tells the build to use the arm-linux-gnu-gcc compiler, and to cross-execute the test binaries during the configure stage using the qemu-arm-static tool. By using a --cross-execute tool you can ensure that all your configure tests can run correctly, which avoids the problem of having to work out things like the size of various target architecture types.After the configure, run waf as usual to build. You can then test the resulting binaries using (for example):qemu-arm-static -L /usr/arm-linux-gnu bin/ldbadd
and it will run using qemu.Using --cross-answers
If you don't have a emulator for your target machine, you will need to use the --cross-answers option. When you specify something like --cross-answers=target.txt the build will place unknown configure tests in target.txt. You then need to edit that file, and change any UNKNOWN answers with the correct answers for your target.For example, you could do this:CC=arm-linux-gnu-gcc waf configure --cross-compile --cross-answers=arm.txt
That will initially create a file like this:Checking simple C program: UNKNOWN
The configure stopped at that point as it needs to know if a simple C program can run before it will continue. If you look in bin/config.log (or in bin/.conf_check_0/) you will see the source code for the program that it was testing.To continue the configure process, you would edit arm.txt and replace UNKNOWN with OK like this:Checking simple C program: OK
The configure will again fail, and you will end up with this in arm.txt:Checking simple C program: OK
building library support: UNKNOWN
Checking for large file support: UNKNOWN
Checking for -D_FILE_OFFSET_BITS=64: UNKNOWN
Checking for WORDS_BIGENDIAN: UNKNOWN
Checking size of char: UNKNOWN
Checking size of int: UNKNOWN
Checking size of long long: UNKNOWN
Checking size of long: UNKNOWN
Checking size of off_t: UNKNOWN
Checking size of short: UNKNOWN
Checking size of size_t: UNKNOWN
Checking size of ssize_t: UNKNOWN
Checking size of dev_t: UNKNOWN
Checking size of ino_t: UNKNOWN
Checking size of time_t: UNKNOWN
Checking size of void*: UNKNOWN
Checking for C99 vsnprintf: UNKNOWN
Checking for HAVE_SECURE_MKSTEMP: UNKNOWN
Note that only the tests that involve running an executable on the target have been added. The other tests are able to be completed by running on the host, and thus do not need a cross-answers entry.You then should replace all the UNKNOWN values with the correct values for your platform. For example:Checking simple C program: OK
building library support: OK
Checking for large file support: OK
Checking for -D_FILE_OFFSET_BITS=64: OK
Checking for WORDS_BIGENDIAN: OK
Checking size of char: "1"
Checking size of int: "4"
Checking size of long long: "8"
Checking size of long: "4"
Checking size of off_t: "8"
Checking size of short: "2"
Checking size of size_t: "4"
Checking size of ssize_t: "4"
Checking size of dev_t: "4"
Checking size of ino_t: "4"
Checking size of time_t: "4"
Checking size of void*: "4"
Checking for C99 vsnprintf: OK
Checking for HAVE_SECURE_MKSTEMP: OK
The right hand side of each line can be in one of several formats, all of which map to a exit code and a returned string. There are also shortcut forms:a OK means that the test should return a exit code of 0, and an empty string
a FAIL or NO means that the test returns a exit code of 255, and an empty string
a UNKNOWN means the test has an unknown result
a "STRING" or 'STRING' means the test has an exit code of 0, and the given string
The general form is:Some message: (RETCODE, RETSTRING)
here are some examples:Some message: (0, "")
Some message: (23, "")
Some message: (0, "a string")
Some message: (1, "another string")
If your configure step completes, but there are still UNKNOWN values in your answers file, then the following message will be displayed:Cross answers file arm.txt is incomplete
and you will need to continue with the iterative process until all answers are filled in

上面的信息是来自samba官网的编译介绍。两种方式都可以成功。我附上自己目前使用的answer.txt:

Checking uname sysname type:"Linux"
Checking uname machine type: "arm"
Checking uname release type: "5.4.0-58-generic"
Checking uname version type: "#64~18.04.1-Ubuntu SMP Wed Dec 9 17:11:11 UTC 2020"
Checking simple C program: "ok"
rpath library support: "ok"
-Wl,--version-script support: "ok"
Checking getconf LFS_CFLAGS: "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
Checking for large file support without additional flags: "ok"
Checking for -D_FILE_OFFSET_BITS=64: "yes"
Checking for -D_LARGE_FILES: "yes"
Checking getconf large file support flags work: "ok"
Checking correct behavior of strtoll: "ok"
Checking for working strptime: "ok"
Checking for C99 vsnprintf: "ok"
Checking for HAVE_SHARED_MMAP: "ok"
Checking for HAVE_MREMAP: "ok"
Checking for HAVE_INCOHERENT_MMAP: "ok"
Checking for HAVE_SECURE_MKSTEMP: "ok"
Checking for HAVE_IFACE_GETIFADDRS: "ok"
Checking for HAVE_IFACE_IFCONF: "ok"
Checking for HAVE_IFACE_IFREQ: "ok"

3. 如果上面的交叉编译的configure都可以成功,那接下来只要make就可以得到相关的library和tools。

libtdb.so.1.3.11    tdbbackup   tdbdump   tdbrestore  tdbtool  tdbtorture

一些实用代码的情况我们看一参考 代码里面文档libtdb-1.3.11.orig\docs\README或者https://tdb.samba.org/

4. 在最后分享一个tdb文件被损害破坏的问题:

./tdbtool /data/settings/DB/paky.tdb
tdb> info
tdb_rec_read bad magic 0xd9fee666 at offset=4783600
Size of file/data: 23068672/480025
Header offset/logical size: 0/23068672
Number of records: 1966
Incompatible hash: no
Active/supported feature flags: 0x00000000/0x00000001
Robust mutexes locking: no
Smallest/average/largest keys: 2/25/41
Smallest/average/largest data: 3/218/43854
Smallest/average/largest padding: 4/71/10973
Number of dead records: 1
Smallest/average/largest dead records: 7938024/7938024/7938024
Number of free records: 1777
Smallest/average/largest free records: 12/8114/4062036
Number of hash chains: 131
Smallest/average/largest hash chains: 0/14/30
Number of uncoalesced records: 1356
Smallest/average/largest uncoalesced runs: 1/8/92
Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: 0/2/1/63/34/0/0
tdb> check
Hashes do not match records
Integrity check for the opened database failed.
tdb>

因为某些异常的发生,tdb的文件里的数据库结构被破坏了,我们没法读出里面的数据了。 这个问题我的处理方式时去修改libtdb的代码试图去修正里面的异常magic number.确保可以尽量的读出所有可以读出的数据,处理流程如下:

  • step 1:修改libtdb的代码试图去修正里面的异常magic number
  • step 2:使用tdbbackup 备份上面修复后的数据库文件
  • step 3:再次检查备份处理数据库文件,确认完整无误。
  • step 4: 删除原来的数据库文件,把备份数据库文件改名成正式文件。

最后附上step1中的修改patch for version 1.3.11:

From b39c2622581421e7136c328e86af2db9a86de4af Mon Sep 17 00:00:00 2001
From: "Paky.Du" <paky.pc.du@gmail.com>
Date: Thu, 28 Jan 2021 15:29:14 +0800
Subject: [PATCH] fix the tdb database bad-magic when read record.---common/io.c | 15 +++++++++++++++1 file changed, 15 insertions(+)diff --git a/common/io.c b/common/io.c
index fe47d18..b2cb242 100755
--- a/common/io.c
+++ b/common/io.c
@@ -645,10 +645,25 @@ int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rif (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1)return -1;if (TDB_BAD_MAGIC(rec)) {
+  #if 0/* Ensure ecode is set for log fn. */tdb->ecode = TDB_ERR_CORRUPT;TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%u\n", rec->magic, offset));return -1;
+  #else
+      //Try to fix the error...
+      if (rec->magic != TDB_MAGIC) {
+      /* this happens when a app is showdown while deleting a record - we should
+         not completely fail when this happens */
+
+          TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_read bad magic 0x%x at offset=%u - fixing\n",
+               rec->magic, offset));
+          //rec->magic = TDB_MAGIC;
+          rec->magic = TDB_DEAD_MAGIC;
+          if (tdb_rec_write(tdb, offset, rec) == -1)
+              return -1;
+      }
+  #endif}return tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0);}
--
2.17.1

Samba TDB 数据库 在嵌入式中的使用相关推荐

  1. 嵌入式数据库在Java中的应用

    嵌入式数据库无需安装,体积小巧,速度又很快,在很多场合可以替代目前流行的MySQL, SQLServer等大中型数据库.本文介绍两种嵌入式数据库产品:Berkeley DB和SQLite,并着重讨论它 ...

  2. Samba服务器在高校网络管理中的应用

    摘要:linux服务器在民办高校的网络管理中,有着广泛的应用前景.Samba服务是linux服务器可以提供的重要网络服务,主要是提供文件和打印共享服务,也能够作为主域控制器(PDC),进行集中的帐户管 ...

  3. android收藏功能demo,Android使用Realm数据库实现App中的收藏功能(代码详解)

    前 言 App数据持久化功能是每个App必不可少的功能,而Android最常用的数据持久化方式主要有以下的五种方式: 使用SharedPreferences存储数据: 文件存储数据: SQLite数据 ...

  4. 将页面多个下拉框的值以字符串拼接方式存放至数据库一个字段中

     1,当页面中有多个值,传入Controller并以字符串拼接方式,以","隔开存放至数据库一个字段中,页面中多个<select name="off"&g ...

  5. 数据库在EF中创建模型

    数据库在EF中创建模型,最简单的理解就是把数据库的字段以及关系映射到项目中,在项目中通过EF框架和LINQ语句直接对数据库数据进行增删改查.下边手把手教你建立模型. 1.建立一个项目,添加新项目,选择 ...

  6. 嵌入式中的中断服务程序

    嵌入式中的中断服务程序 中断是嵌入式系统中重要的组成部分,但是在标准 C 中不包含中断.许多编译开发商在标准 C 上增加了对中断的支持,提供新的关键字用于标示中断服务程序(ISR),类似于__inte ...

  7. 嵌入式中常见的几个死循环:

    嵌入式中常见的几个死循环: (1) 操作系统是死循环: (2) WIN32 程序是死循环: (3) 嵌入式系统软件是死循环: (4) 多线程程序的线程处理函数是死循环. 你可能会辩驳,大声说:&quo ...

  8. 上下位机通讯协议_嵌入式中自定义协议的一些典型例子

    关于自定义协议,对于会的人很简单,对于不会的人就摸不着头脑.下面分享一些关于自定义协议的笔记. 什么是协议? 协议这个概念我觉得挺杂的.就像嵌入式的概念一样,说法不一,比如大家常常争论FPGA是不是嵌 ...

  9. MySQL工作中的实际用_数据库在工作中的应用,以及什么是MySQL?

    数据库在工作中的应用: 1.软件都需要数据库(database)作为后台支撑 2.部署测试环境需要安装.配置数据库 3.数据库(database)中构造初始化数据 4.测试执行过程中需要验证数据库(d ...

  10. MySQL删除s表命令_SQLServer数据库sql语句中----删除表数据drop、truncate和delete的用法...

    本文主要向大家介绍了SQLServer数据库sql语句中----删除表数据drop.truncate和delete的用法,通过具体的内容向大家展现,希望对大家学习SQLServer数据库有所帮助. 虽 ...

最新文章

  1. 伍六七带你学算法 入门篇-拼写单词
  2. 关于jsp和eclipse服务器端的相关配置和JS的区别
  3. c语言bool怎么用_C语言中的一维数组和二维数组什么?怎么用?
  4. C#中几种换行符,不同操作系统各不相同【转】
  5. 游戏运行时报0xc000007b错的解决办法
  6. [转]wchar_t char std::string std::wstring CString 转换
  7. 安装oracle后电脑无法启动,求救,Oracle11g安装成功后,总是无法启动
  8. 一本通网站 1378:最短路径(shopth)
  9. 理解_授权数据模型_Spring Security OAuth2.0认证授权---springcloud工作笔记112
  10. securecrt 中文横着显示解决
  11. 最受欢迎的 Top语言及其 Top 10漏洞
  12. 单机多实例Tomcat部署
  13. SVN删除某版本解决办法
  14. IBM Rational Appscan使用之扫描结果分析
  15. java jco sap 重连_SAP R3和JAVA交换数据之JCO
  16. 哔哩哔哩HLB站缓存合并电脑版链接:https://wwa.lanzoui.com/b016vmouf版本:1.1公告:1、支持旧版(blv)合并2、新增提取音频功能3、修复合并失败的bug
  17. 统计学三种相关系数【pearson、spearman、kendall】
  18. [任务书+论文+PPT+源码]基于Android与多媒体的英文学习APP的设计与实现
  19. Python语言程序设计 - 北京理工大学 网课所有资料(源码,pdf,ppt课件,视频等)
  20. 阿里云国际站和阿里云国内站有什么区别?

热门文章

  1. 亚马逊资源名称 (ARN) 和 AWS 服务命名空间
  2. sucess - money - freedom
  3. 无盘服务器吃鸡卡,网吧吃鸡卡-来看看你所在的网吧配置是否达标!
  4. KFC肯德基带给孩子的危害(转)
  5. 2022考研笔记-英语(五种记忆单词的方法)
  6. c语言中while(a)、if(a)、while(!a)、if(!a)、if(%a)是什么意思?
  7. flash人物原地走路_flash如何做人物走路
  8. 苹果6系统怎么更新不了_苹果手机系统怎么降级
  9. 架构必看:12306抢票亿级流量架构演进(图解+秒懂+史上最全)
  10. 概率论中PDF、PMF和CDF的区别与联系