sfdb.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /***************************************************************
  2. * @file sfdb.c
  3. * @brief
  4. * @author WKJay
  5. * @Version
  6. * @Date 2023-02-13
  7. ***************************************************************/
  8. #include "sfdb.h"
  9. #define FILE_HEADER "SFDB002" // Simple file database
  10. #define DB_HDR_OFFSET 0
  11. #define DB_DATA_OFFSET 512
  12. #define MAX_RECORD_LEN 512
  13. static int seek_and_write(sfdb_t *db, uint8_t *buf, uint32_t offset, uint32_t sz) {
  14. int ret = -1;
  15. if (db->fs->sk(db->fd, offset) != offset) {
  16. SF_LOG("seek failed");
  17. return -1;
  18. }
  19. ret = db->fs->wr(db->fd, buf, sz);
  20. if (db->flags & SFDB_SYNC) db->fs->sy(db->fd);
  21. return ret;
  22. }
  23. static int seek_and_read(sfdb_t *db, uint8_t *buf, uint32_t offset, uint32_t sz) {
  24. if (db->fs->sk(db->fd, offset) != offset) {
  25. SF_LOG("seek failed");
  26. return -1;
  27. }
  28. return db->fs->rd(db->fd, buf, sz);
  29. }
  30. static int sfdb_new_db(sfdb_t *db, uint32_t max_record_num, uint32_t record_len) {
  31. SF_MEMCPY(db->hdr.magic, FILE_HEADER, sizeof(db->hdr.magic));
  32. db->hdr.max_record_num = max_record_num;
  33. db->hdr.record_len = record_len;
  34. if (seek_and_write(db, (uint8_t *)&db->hdr, 0, sizeof(db->hdr)) != sizeof(db->hdr)) {
  35. return -1;
  36. }
  37. return 0;
  38. }
  39. static int sfdb_get_db_info(sfdb_t *db) {
  40. if (seek_and_read(db, (uint8_t *)&db->hdr, 0, sizeof(db->hdr)) != sizeof(db->hdr)) {
  41. return -1;
  42. }
  43. return 0;
  44. }
  45. int sfdb_close(sfdb_t *db) {
  46. if (db->state != SFDB_STATE_OPENED) {
  47. SF_LOG("%s not opened", db->path);
  48. return -1;
  49. }
  50. db->fs->cl(db->fd);
  51. db->state = SFDB_STATE_CLOSED;
  52. return 0;
  53. }
  54. /**
  55. * @brief 创建一个SFDB
  56. * @param path: 数据库路径
  57. * @param db: 数据库结构体
  58. * @param max_record_num: 最大数据量
  59. * @param record_len: 单条数据长度
  60. * @param overwrite: 当 record_len 和 max_record_num 参数和数据库保存的参数不匹配时
  61. * 若该参数为1则进行覆盖
  62. * @return return
  63. */
  64. int sfdb_open(sfdb_t *db, sfdb_cfg_t *cfg) {
  65. uint8_t retry_cnt = 0;
  66. if (cfg->record_len > MAX_RECORD_LEN) {
  67. SF_LOG("record len:%d is larger than max record len:%d", cfg->record_len, MAX_RECORD_LEN);
  68. return -1;
  69. }
  70. retry:
  71. SF_MEMSET(db, 0, sizeof(sfdb_t));
  72. db->fs = &sfdb_fs;
  73. db->path = cfg->path;
  74. db->flags = cfg->flags;
  75. if (db->fs->op(db, db->path, SFDB_O_READ | SFDB_O_WRITE) < 0) {
  76. SF_LOG("open file %s failed. try to create.", db->path);
  77. if (db->fs->op(db, db->path, SFDB_O_CREATE | SFDB_O_READ | SFDB_O_WRITE) < 0) {
  78. SF_LOG("create file %s failed.", db->path);
  79. return -1;
  80. }
  81. db->state = SFDB_STATE_OPENED;
  82. if (sfdb_new_db(db, cfg->max_record_num, cfg->record_len) < 0) {
  83. SF_LOG("create new database failed.");
  84. goto err_close_db;
  85. }
  86. } else {
  87. db->state = SFDB_STATE_OPENED;
  88. if (sfdb_get_db_info(db) < 0) {
  89. SF_LOG("get database information failed.");
  90. goto try_overwrite;
  91. }
  92. if (db->hdr.max_record_num != cfg->max_record_num) {
  93. SF_LOG("max record num not match.");
  94. goto try_overwrite;
  95. }
  96. if (db->hdr.record_len != cfg->record_len) {
  97. SF_LOG("record len not match");
  98. goto try_overwrite;
  99. }
  100. }
  101. return 0;
  102. try_overwrite:
  103. if ((db->flags & SFDB_OVERWRITE) == 0) {
  104. goto err_close_db;
  105. }
  106. if (retry_cnt++ < 1) {
  107. SF_LOG("try to overwrite sfdb %s.", db->path);
  108. } else {
  109. SF_LOG(" overwrite sfdb %s failed.", db->path);
  110. goto err_close_db;
  111. }
  112. db->fs->cl(db->fd);
  113. db->state = SFDB_STATE_CLOSED;
  114. if (sfdb_delete(db) < 0) {
  115. SF_LOG("delete %s failed.", db->path);
  116. goto err_close_db;
  117. }
  118. goto retry;
  119. err_close_db:
  120. SF_LOG("open %s failed.", db->path);
  121. db->fs->cl(db->fd);
  122. db->state = SFDB_STATE_CLOSED;
  123. return -1;
  124. }
  125. int sfdb_append(sfdb_t *db, uint8_t *buf, uint16_t sz) {
  126. uint32_t offset = 0;
  127. if (sz != db->hdr.record_len) {
  128. SF_LOG("data size %d is invalid(should be %d).", sz, db->hdr.record_len);
  129. return -1;
  130. }
  131. if (db->fd < 0) {
  132. SF_LOG("invalid fd");
  133. return -1;
  134. }
  135. /* 计算本次插入数据的索引 */
  136. if (db->hdr.record_index >= (db->hdr.max_record_num - 1)) {
  137. db->hdr.record_index = 0;
  138. } else {
  139. db->hdr.record_index++;
  140. }
  141. if (db->hdr.record_count < db->hdr.max_record_num) {
  142. db->hdr.record_count++;
  143. }
  144. // 当前为第一条时重置索引为0
  145. if (db->hdr.record_count == 1) db->hdr.record_index = 0;
  146. /* 根据索引计算数据存储的偏移 */
  147. offset = db->hdr.record_index * db->hdr.record_len + DB_DATA_OFFSET;
  148. /* 写入数据 */
  149. if (seek_and_write(db, buf, offset, sz) != sz) {
  150. SF_LOG("write data failed.");
  151. return -1;
  152. }
  153. /* 写入头 */
  154. if (seek_and_write(db, (uint8_t *)&db->hdr, 0, sizeof(db->hdr)) != sizeof(db->hdr)) {
  155. SF_LOG("update hdr failed.");
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. /**
  161. * @brief 读数据库数据
  162. * @param db 数据库对象
  163. * @param buf 读取数据的缓冲区
  164. * @param buf_sz 缓冲区大小
  165. * @param offset 读取的起始偏移地址(从0开始,且0表示最新一条数据)
  166. * @param num 读取的数据量
  167. * @param order 读取顺序 SFDB_READ_ASC:从旧到新 SFDB_READ_DESC:从新到旧
  168. * @note
  169. * 通过该接口读取的数组第0个元素对应当前集合中最早存入的数据,数组下标最大的即为最近一次存入的数据
  170. * @return 成功:返回读取的数据量 失败:-1
  171. */
  172. int sfdb_read(sfdb_t *db, uint8_t *buf, uint32_t buf_sz, uint32_t offset, uint32_t num, uint8_t order) {
  173. uint32_t data_count = 0, read_num = 0, start_index = 0, read_total = 0;
  174. if (db->fd < 0) {
  175. SF_LOG("invalid fd");
  176. return -1;
  177. }
  178. if (buf_sz < num * db->hdr.record_len) {
  179. SF_LOG("provided buffer size %d < %d (required).", buf_sz, num * db->hdr.record_len);
  180. return -1;
  181. }
  182. /* 获取存储量总数 */
  183. data_count = db->hdr.record_count;
  184. if (data_count > db->hdr.max_record_num) data_count = db->hdr.max_record_num;
  185. // 没有数据时直接返回
  186. if (data_count <= 0) return 0;
  187. if (offset >= data_count) return 0;
  188. if (num == 0) return 0;
  189. /* 根据提供的起始偏移和读数数量来计算实际能够读取的数量 */
  190. if ((offset + num) > data_count) num = data_count - offset;
  191. read_total = num;
  192. /* 计算起始读取索引 */
  193. if (order == SFDB_READ_ASC) { // 从旧到新
  194. if (db->hdr.record_index < (db->hdr.record_count - offset - 1)) {
  195. start_index = db->hdr.record_index + offset + 1;
  196. } else {
  197. start_index = db->hdr.record_index + offset + 1 - db->hdr.record_count;
  198. }
  199. } else { // 从新到旧
  200. if (db->hdr.record_index < (offset + num - 1)) { // 存在一部分数据在底部
  201. start_index = db->hdr.record_count + db->hdr.record_index - (offset + num - 1);
  202. } else {
  203. start_index = db->hdr.record_index - (offset + num - 1);
  204. }
  205. }
  206. while (num) {
  207. uint32_t read_offset = 0, read_len = 0;
  208. read_offset = DB_DATA_OFFSET + start_index * db->hdr.record_len;
  209. if (start_index + num > db->hdr.max_record_num - 1) {
  210. // 当前索引在数据底部,并且有一部分数据在头部,需要二次读取
  211. read_num = db->hdr.max_record_num - start_index;
  212. } else {
  213. read_num = num;
  214. }
  215. read_len = read_num * db->hdr.record_len;
  216. if (seek_and_read(db, buf, read_offset, read_len) != read_len) {
  217. SF_LOG("read data failed.");
  218. return -1;
  219. }
  220. num -= read_num;
  221. start_index += read_num;
  222. if (start_index >= db->hdr.max_record_num) start_index = 0;
  223. buf += read_len;
  224. }
  225. return read_total;
  226. }
  227. /**
  228. * @brief 读数据库信息
  229. * @param db 数据库对象
  230. * @param info 数据库信息结构体
  231. * @return 成功 0 失败 -1
  232. */
  233. int sfdb_read_info(sfdb_t *db, sfdb_info_t *info) {
  234. if (db->state != SFDB_STATE_OPENED) {
  235. SF_LOG("db %s not opened.", db->path);
  236. return -1;
  237. }
  238. info->record_index = db->hdr.record_index;
  239. info->record_count = db->hdr.record_count;
  240. info->max_record_num = db->hdr.max_record_num;
  241. info->record_len = db->hdr.record_len;
  242. return 0;
  243. }
  244. /**
  245. * @brief 重置数据库(清除数据库中的数据)
  246. * @param db: 数据库对象
  247. * @return 成功:0 失败:-1
  248. */
  249. int sfdb_reset(sfdb_t *db) {
  250. if (db->state != SFDB_STATE_OPENED) {
  251. SF_LOG("db %s not opened.", db->path);
  252. return -1;
  253. }
  254. db->hdr.record_index = 0;
  255. db->hdr.record_count = 0;
  256. /* 更新头 */
  257. if (seek_and_write(db, (uint8_t *)&db->hdr, 0, sizeof(db->hdr)) != sizeof(db->hdr)) {
  258. SF_LOG("update hdr failed.");
  259. return -1;
  260. }
  261. return 0;
  262. }
  263. /**
  264. * @brief 删除数据库
  265. * @param db 数据库对象
  266. * @return 成功:0 失败:-1
  267. */
  268. int sfdb_delete(sfdb_t *db) { return unlink(db->path); }
  269. /**
  270. * @brief 同步数据库缓存到文件
  271. * @param db 数据库对象
  272. * @return 成功:0 失败:-1
  273. */
  274. int sfdb_sync(sfdb_t *db) { return db->fs->sy(db->fd); }