heroku-tokyotyrant 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (340) hide show
  1. data/COPYING +504 -0
  2. data/README.rdoc +231 -0
  3. data/Rakefile +72 -0
  4. data/benchmarks/balancer.rb +101 -0
  5. data/benchmarks/bulk_db.rb +74 -0
  6. data/benchmarks/bulk_table.rb +87 -0
  7. data/benchmarks/db.rb +114 -0
  8. data/benchmarks/table.rb +161 -0
  9. data/ext/extconf.rb +43 -0
  10. data/ext/tokyo/bin/tcamgr +0 -0
  11. data/ext/tokyo/bin/tcamttest +0 -0
  12. data/ext/tokyo/bin/tcatest +0 -0
  13. data/ext/tokyo/bin/tcbmgr +0 -0
  14. data/ext/tokyo/bin/tcbmttest +0 -0
  15. data/ext/tokyo/bin/tcbtest +0 -0
  16. data/ext/tokyo/bin/tcfmgr +0 -0
  17. data/ext/tokyo/bin/tcfmttest +0 -0
  18. data/ext/tokyo/bin/tcftest +0 -0
  19. data/ext/tokyo/bin/tchmgr +0 -0
  20. data/ext/tokyo/bin/tchmttest +0 -0
  21. data/ext/tokyo/bin/tchtest +0 -0
  22. data/ext/tokyo/bin/tcrmgr +0 -0
  23. data/ext/tokyo/bin/tcrmttest +0 -0
  24. data/ext/tokyo/bin/tcrtest +0 -0
  25. data/ext/tokyo/bin/tctmgr +0 -0
  26. data/ext/tokyo/bin/tctmttest +0 -0
  27. data/ext/tokyo/bin/tcttest +0 -0
  28. data/ext/tokyo/bin/tcucodec +0 -0
  29. data/ext/tokyo/bin/tcumttest +0 -0
  30. data/ext/tokyo/bin/tcutest +0 -0
  31. data/ext/tokyo/bin/ttserver +0 -0
  32. data/ext/tokyo/bin/ttulmgr +0 -0
  33. data/ext/tokyo/bin/ttultest +0 -0
  34. data/ext/tokyo/include/tcadb.h +548 -0
  35. data/ext/tokyo/include/tcbdb.h +1101 -0
  36. data/ext/tokyo/include/tcfdb.h +858 -0
  37. data/ext/tokyo/include/tchdb.h +871 -0
  38. data/ext/tokyo/include/tcrdb.h +801 -0
  39. data/ext/tokyo/include/tctdb.h +1086 -0
  40. data/ext/tokyo/include/tculog.h +392 -0
  41. data/ext/tokyo/include/tcutil.h +4184 -0
  42. data/ext/tokyo/include/ttutil.h +494 -0
  43. data/ext/tokyo/lib/libtokyocabinet.9.4.0.dylib +0 -0
  44. data/ext/tokyo/lib/libtokyocabinet.9.dylib +0 -0
  45. data/ext/tokyo/lib/libtokyocabinet.a +0 -0
  46. data/ext/tokyo/lib/libtokyocabinet.dylib +0 -0
  47. data/ext/tokyo/lib/libtokyotyrant.3.22.0.dylib +0 -0
  48. data/ext/tokyo/lib/libtokyotyrant.3.dylib +0 -0
  49. data/ext/tokyo/lib/libtokyotyrant.a +0 -0
  50. data/ext/tokyo/lib/libtokyotyrant.dylib +0 -0
  51. data/ext/tokyo/lib/pkgconfig/tokyocabinet.pc +14 -0
  52. data/ext/tokyo/lib/pkgconfig/tokyotyrant.pc +14 -0
  53. data/ext/tokyo/lib/ttskeldir.bundle +0 -0
  54. data/ext/tokyo/lib/ttskelmock.bundle +0 -0
  55. data/ext/tokyo/lib/ttskelnull.bundle +0 -0
  56. data/ext/tokyo/lib/ttskelproxy.bundle +0 -0
  57. data/ext/tokyo/libexec/tcawmgr.cgi +0 -0
  58. data/ext/tokyo/sbin/ttservctl +163 -0
  59. data/ext/tokyo/share/man/man1/tcamgr.1 +97 -0
  60. data/ext/tokyo/share/man/man1/tcamttest.1 +35 -0
  61. data/ext/tokyo/share/man/man1/tcatest.1 +55 -0
  62. data/ext/tokyo/share/man/man1/tcbmgr.1 +125 -0
  63. data/ext/tokyo/share/man/man1/tcbmttest.1 +81 -0
  64. data/ext/tokyo/share/man/man1/tcbtest.1 +107 -0
  65. data/ext/tokyo/share/man/man1/tcfmgr.1 +98 -0
  66. data/ext/tokyo/share/man/man1/tcfmttest.1 +62 -0
  67. data/ext/tokyo/share/man/man1/tcftest.1 +73 -0
  68. data/ext/tokyo/share/man/man1/tchmgr.1 +110 -0
  69. data/ext/tokyo/share/man/man1/tchmttest.1 +85 -0
  70. data/ext/tokyo/share/man/man1/tchtest.1 +95 -0
  71. data/ext/tokyo/share/man/man1/tcrmgr.1 +164 -0
  72. data/ext/tokyo/share/man/man1/tcrmttest.1 +55 -0
  73. data/ext/tokyo/share/man/man1/tcrtest.1 +89 -0
  74. data/ext/tokyo/share/man/man1/tctmgr.1 +140 -0
  75. data/ext/tokyo/share/man/man1/tctmttest.1 +92 -0
  76. data/ext/tokyo/share/man/man1/tcttest.1 +105 -0
  77. data/ext/tokyo/share/man/man1/tcucodec.1 +162 -0
  78. data/ext/tokyo/share/man/man1/tcumttest.1 +41 -0
  79. data/ext/tokyo/share/man/man1/tcutest.1 +81 -0
  80. data/ext/tokyo/share/man/man1/ttserver.1 +84 -0
  81. data/ext/tokyo/share/man/man1/ttulmgr.1 +40 -0
  82. data/ext/tokyo/share/man/man1/ttultest.1 +16 -0
  83. data/ext/tokyo/share/man/man3/tcadb.3 +676 -0
  84. data/ext/tokyo/share/man/man3/tcbdb.3 +1355 -0
  85. data/ext/tokyo/share/man/man3/tcfdb.3 +975 -0
  86. data/ext/tokyo/share/man/man3/tchdb.3 +898 -0
  87. data/ext/tokyo/share/man/man3/tclist.3 +1 -0
  88. data/ext/tokyo/share/man/man3/tcmap.3 +1 -0
  89. data/ext/tokyo/share/man/man3/tcmdb.3 +1 -0
  90. data/ext/tokyo/share/man/man3/tcmpool.3 +1 -0
  91. data/ext/tokyo/share/man/man3/tcrdb.3 +1309 -0
  92. data/ext/tokyo/share/man/man3/tctdb.3 +1110 -0
  93. data/ext/tokyo/share/man/man3/tctree.3 +1 -0
  94. data/ext/tokyo/share/man/man3/tculog.3 +15 -0
  95. data/ext/tokyo/share/man/man3/tcutil.3 +4518 -0
  96. data/ext/tokyo/share/man/man3/tcxstr.3 +1 -0
  97. data/ext/tokyo/share/man/man3/tokyocabinet.3 +132 -0
  98. data/ext/tokyo/share/man/man3/ttutil.3 +14 -0
  99. data/ext/tokyo/share/man/man8/ttservctl.8 +37 -0
  100. data/ext/tokyo/share/tokyocabinet/COPYING +504 -0
  101. data/ext/tokyo/share/tokyocabinet/ChangeLog +1252 -0
  102. data/ext/tokyo/share/tokyocabinet/THANKS +12 -0
  103. data/ext/tokyo/share/tokyocabinet/doc/benchmark.pdf +0 -0
  104. data/ext/tokyo/share/tokyocabinet/doc/common.css +211 -0
  105. data/ext/tokyo/share/tokyocabinet/doc/icon16.png +0 -0
  106. data/ext/tokyo/share/tokyocabinet/doc/index.html +156 -0
  107. data/ext/tokyo/share/tokyocabinet/doc/index.ja.html +197 -0
  108. data/ext/tokyo/share/tokyocabinet/doc/logo-ja.png +0 -0
  109. data/ext/tokyo/share/tokyocabinet/doc/logo.png +0 -0
  110. data/ext/tokyo/share/tokyocabinet/doc/spex-en.html +7145 -0
  111. data/ext/tokyo/share/tokyocabinet/doc/spex-ja.html +7476 -0
  112. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.pdf +0 -0
  113. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.ppt +0 -0
  114. data/ext/tokyo/share/tokyotyrant/COPYING +504 -0
  115. data/ext/tokyo/share/tokyotyrant/ChangeLog +578 -0
  116. data/ext/tokyo/share/tokyotyrant/THANKS +15 -0
  117. data/ext/tokyo/share/tokyotyrant/doc/common.css +211 -0
  118. data/ext/tokyo/share/tokyotyrant/doc/index.html +79 -0
  119. data/ext/tokyo/share/tokyotyrant/doc/spex.html +2264 -0
  120. data/ext/tokyo/share/tokyotyrant/ext/mapreduce.lua +57 -0
  121. data/ext/tokyo/share/tokyotyrant/ext/queue.lua +55 -0
  122. data/ext/tokyo/share/tokyotyrant/ext/senatus.lua +532 -0
  123. data/ext/tokyo/share/tokyotyrant/ext/usherette.lua +438 -0
  124. data/ext/tokyo_tyrant.c +147 -0
  125. data/ext/tokyo_tyrant.h +48 -0
  126. data/ext/tokyo_tyrant_db.c +227 -0
  127. data/ext/tokyo_tyrant_db.h +8 -0
  128. data/ext/tokyo_tyrant_module.c +453 -0
  129. data/ext/tokyo_tyrant_module.h +10 -0
  130. data/ext/tokyo_tyrant_query.c +226 -0
  131. data/ext/tokyo_tyrant_query.h +9 -0
  132. data/ext/tokyo_tyrant_table.c +319 -0
  133. data/ext/tokyo_tyrant_table.h +8 -0
  134. data/ext/tokyocabinet-1.4.41/COPYING +504 -0
  135. data/ext/tokyocabinet-1.4.41/ChangeLog +1252 -0
  136. data/ext/tokyocabinet-1.4.41/Makefile.in +825 -0
  137. data/ext/tokyocabinet-1.4.41/README +38 -0
  138. data/ext/tokyocabinet-1.4.41/THANKS +12 -0
  139. data/ext/tokyocabinet-1.4.41/bros/Makefile +133 -0
  140. data/ext/tokyocabinet-1.4.41/bros/bdbtest.c +438 -0
  141. data/ext/tokyocabinet-1.4.41/bros/cdbtest.c +219 -0
  142. data/ext/tokyocabinet-1.4.41/bros/cmpsqltctest.c +186 -0
  143. data/ext/tokyocabinet-1.4.41/bros/gdbmtest.c +216 -0
  144. data/ext/tokyocabinet-1.4.41/bros/mapreporter +72 -0
  145. data/ext/tokyocabinet-1.4.41/bros/maptest.cc +677 -0
  146. data/ext/tokyocabinet-1.4.41/bros/ndbmtest.c +204 -0
  147. data/ext/tokyocabinet-1.4.41/bros/qdbmtest.c +375 -0
  148. data/ext/tokyocabinet-1.4.41/bros/reporter +141 -0
  149. data/ext/tokyocabinet-1.4.41/bros/result.xls +0 -0
  150. data/ext/tokyocabinet-1.4.41/bros/sdbmtest.c +204 -0
  151. data/ext/tokyocabinet-1.4.41/bros/sqltest.c +404 -0
  152. data/ext/tokyocabinet-1.4.41/bros/tctest.c +748 -0
  153. data/ext/tokyocabinet-1.4.41/bros/tdbtest.c +205 -0
  154. data/ext/tokyocabinet-1.4.41/configure +7402 -0
  155. data/ext/tokyocabinet-1.4.41/configure.in +362 -0
  156. data/ext/tokyocabinet-1.4.41/doc/benchmark.pdf +0 -0
  157. data/ext/tokyocabinet-1.4.41/doc/common.css +211 -0
  158. data/ext/tokyocabinet-1.4.41/doc/icon16.png +0 -0
  159. data/ext/tokyocabinet-1.4.41/doc/index.html +156 -0
  160. data/ext/tokyocabinet-1.4.41/doc/index.ja.html +197 -0
  161. data/ext/tokyocabinet-1.4.41/doc/logo-ja.png +0 -0
  162. data/ext/tokyocabinet-1.4.41/doc/logo.png +0 -0
  163. data/ext/tokyocabinet-1.4.41/doc/spex-en.html +7145 -0
  164. data/ext/tokyocabinet-1.4.41/doc/spex-ja.html +7476 -0
  165. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.pdf +0 -0
  166. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.ppt +0 -0
  167. data/ext/tokyocabinet-1.4.41/example/Makefile +113 -0
  168. data/ext/tokyocabinet-1.4.41/example/tcadbex.c +55 -0
  169. data/ext/tokyocabinet-1.4.41/example/tcbdbex.c +64 -0
  170. data/ext/tokyocabinet-1.4.41/example/tcfdbex.c +60 -0
  171. data/ext/tokyocabinet-1.4.41/example/tchdbex.c +60 -0
  172. data/ext/tokyocabinet-1.4.41/example/tctchat.c +97 -0
  173. data/ext/tokyocabinet-1.4.41/example/tctchat.tmpl +141 -0
  174. data/ext/tokyocabinet-1.4.41/example/tctdbex.c +85 -0
  175. data/ext/tokyocabinet-1.4.41/example/tctsearch.c +95 -0
  176. data/ext/tokyocabinet-1.4.41/example/tctsearch.tmpl +122 -0
  177. data/ext/tokyocabinet-1.4.41/example/tcutilex.c +77 -0
  178. data/ext/tokyocabinet-1.4.41/f.tsv +2 -0
  179. data/ext/tokyocabinet-1.4.41/lab/calccomp +118 -0
  180. data/ext/tokyocabinet-1.4.41/lab/datechange +56 -0
  181. data/ext/tokyocabinet-1.4.41/lab/diffcheck +45 -0
  182. data/ext/tokyocabinet-1.4.41/lab/htmltotsv +102 -0
  183. data/ext/tokyocabinet-1.4.41/lab/magic +19 -0
  184. data/ext/tokyocabinet-1.4.41/lab/printenv.cgi +27 -0
  185. data/ext/tokyocabinet-1.4.41/lab/stepcount +26 -0
  186. data/ext/tokyocabinet-1.4.41/lab/stopwatch +61 -0
  187. data/ext/tokyocabinet-1.4.41/lab/tabcheck +43 -0
  188. data/ext/tokyocabinet-1.4.41/lab/wgettsv +239 -0
  189. data/ext/tokyocabinet-1.4.41/lab/widthcheck +57 -0
  190. data/ext/tokyocabinet-1.4.41/man/htmltoman +104 -0
  191. data/ext/tokyocabinet-1.4.41/man/tcadb.3 +676 -0
  192. data/ext/tokyocabinet-1.4.41/man/tcamgr.1 +97 -0
  193. data/ext/tokyocabinet-1.4.41/man/tcamttest.1 +35 -0
  194. data/ext/tokyocabinet-1.4.41/man/tcatest.1 +55 -0
  195. data/ext/tokyocabinet-1.4.41/man/tcbdb.3 +1355 -0
  196. data/ext/tokyocabinet-1.4.41/man/tcbmgr.1 +125 -0
  197. data/ext/tokyocabinet-1.4.41/man/tcbmttest.1 +81 -0
  198. data/ext/tokyocabinet-1.4.41/man/tcbtest.1 +107 -0
  199. data/ext/tokyocabinet-1.4.41/man/tcfdb.3 +975 -0
  200. data/ext/tokyocabinet-1.4.41/man/tcfmgr.1 +98 -0
  201. data/ext/tokyocabinet-1.4.41/man/tcfmttest.1 +62 -0
  202. data/ext/tokyocabinet-1.4.41/man/tcftest.1 +73 -0
  203. data/ext/tokyocabinet-1.4.41/man/tchdb.3 +898 -0
  204. data/ext/tokyocabinet-1.4.41/man/tchmgr.1 +110 -0
  205. data/ext/tokyocabinet-1.4.41/man/tchmttest.1 +85 -0
  206. data/ext/tokyocabinet-1.4.41/man/tchtest.1 +95 -0
  207. data/ext/tokyocabinet-1.4.41/man/tclist.3 +1 -0
  208. data/ext/tokyocabinet-1.4.41/man/tcmap.3 +1 -0
  209. data/ext/tokyocabinet-1.4.41/man/tcmdb.3 +1 -0
  210. data/ext/tokyocabinet-1.4.41/man/tcmpool.3 +1 -0
  211. data/ext/tokyocabinet-1.4.41/man/tctdb.3 +1110 -0
  212. data/ext/tokyocabinet-1.4.41/man/tctmgr.1 +140 -0
  213. data/ext/tokyocabinet-1.4.41/man/tctmttest.1 +92 -0
  214. data/ext/tokyocabinet-1.4.41/man/tctree.3 +1 -0
  215. data/ext/tokyocabinet-1.4.41/man/tcttest.1 +105 -0
  216. data/ext/tokyocabinet-1.4.41/man/tcucodec.1 +162 -0
  217. data/ext/tokyocabinet-1.4.41/man/tcumttest.1 +41 -0
  218. data/ext/tokyocabinet-1.4.41/man/tcutest.1 +81 -0
  219. data/ext/tokyocabinet-1.4.41/man/tcutil.3 +4518 -0
  220. data/ext/tokyocabinet-1.4.41/man/tcxstr.3 +1 -0
  221. data/ext/tokyocabinet-1.4.41/man/tokyocabinet.3 +132 -0
  222. data/ext/tokyocabinet-1.4.41/md5.c +381 -0
  223. data/ext/tokyocabinet-1.4.41/md5.h +101 -0
  224. data/ext/tokyocabinet-1.4.41/myconf.c +493 -0
  225. data/ext/tokyocabinet-1.4.41/myconf.h +549 -0
  226. data/ext/tokyocabinet-1.4.41/tcadb.c +4339 -0
  227. data/ext/tokyocabinet-1.4.41/tcadb.h +548 -0
  228. data/ext/tokyocabinet-1.4.41/tcamgr.c +1019 -0
  229. data/ext/tokyocabinet-1.4.41/tcamttest.c +542 -0
  230. data/ext/tokyocabinet-1.4.41/tcatest.c +1845 -0
  231. data/ext/tokyocabinet-1.4.41/tcawmgr.c +482 -0
  232. data/ext/tokyocabinet-1.4.41/tcbdb.c +4180 -0
  233. data/ext/tokyocabinet-1.4.41/tcbdb.h +1101 -0
  234. data/ext/tokyocabinet-1.4.41/tcbmgr.c +1012 -0
  235. data/ext/tokyocabinet-1.4.41/tcbmttest.c +1810 -0
  236. data/ext/tokyocabinet-1.4.41/tcbtest.c +2586 -0
  237. data/ext/tokyocabinet-1.4.41/tcfdb.c +2746 -0
  238. data/ext/tokyocabinet-1.4.41/tcfdb.h +858 -0
  239. data/ext/tokyocabinet-1.4.41/tcfmgr.c +786 -0
  240. data/ext/tokyocabinet-1.4.41/tcfmttest.c +1220 -0
  241. data/ext/tokyocabinet-1.4.41/tcftest.c +1695 -0
  242. data/ext/tokyocabinet-1.4.41/tchdb.c +5153 -0
  243. data/ext/tokyocabinet-1.4.41/tchdb.h +871 -0
  244. data/ext/tokyocabinet-1.4.41/tchmgr.c +842 -0
  245. data/ext/tokyocabinet-1.4.41/tchmttest.c +1757 -0
  246. data/ext/tokyocabinet-1.4.41/tchtest.c +2129 -0
  247. data/ext/tokyocabinet-1.4.41/tctdb.c +6199 -0
  248. data/ext/tokyocabinet-1.4.41/tctdb.h +1086 -0
  249. data/ext/tokyocabinet-1.4.41/tctmgr.c +1241 -0
  250. data/ext/tokyocabinet-1.4.41/tctmttest.c +1563 -0
  251. data/ext/tokyocabinet-1.4.41/tcttest.c +2062 -0
  252. data/ext/tokyocabinet-1.4.41/tcucodec.c +1357 -0
  253. data/ext/tokyocabinet-1.4.41/tcumttest.c +578 -0
  254. data/ext/tokyocabinet-1.4.41/tcutest.c +1875 -0
  255. data/ext/tokyocabinet-1.4.41/tcutil.c +10528 -0
  256. data/ext/tokyocabinet-1.4.41/tcutil.h +4184 -0
  257. data/ext/tokyocabinet-1.4.41/tokyocabinet.idl +336 -0
  258. data/ext/tokyocabinet-1.4.41/tokyocabinet.pc.in +14 -0
  259. data/ext/tokyotyrant-1.1.39/COPYING +504 -0
  260. data/ext/tokyotyrant-1.1.39/ChangeLog +578 -0
  261. data/ext/tokyotyrant-1.1.39/Makefile.in +365 -0
  262. data/ext/tokyotyrant-1.1.39/README +38 -0
  263. data/ext/tokyotyrant-1.1.39/THANKS +15 -0
  264. data/ext/tokyotyrant-1.1.39/configure +6979 -0
  265. data/ext/tokyotyrant-1.1.39/configure.in +300 -0
  266. data/ext/tokyotyrant-1.1.39/doc/common.css +211 -0
  267. data/ext/tokyotyrant-1.1.39/doc/index.html +79 -0
  268. data/ext/tokyotyrant-1.1.39/doc/spex.html +2264 -0
  269. data/ext/tokyotyrant-1.1.39/example/Makefile +68 -0
  270. data/ext/tokyotyrant-1.1.39/example/httptest.pl +88 -0
  271. data/ext/tokyotyrant-1.1.39/example/mcftest.pl +39 -0
  272. data/ext/tokyotyrant-1.1.39/example/mctest.pl +43 -0
  273. data/ext/tokyotyrant-1.1.39/example/tcrdbex +0 -0
  274. data/ext/tokyotyrant-1.1.39/example/tcrdbex.c +49 -0
  275. data/ext/tokyotyrant-1.1.39/example/tcrdbex.o +0 -0
  276. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex +0 -0
  277. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.c +79 -0
  278. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.o +0 -0
  279. data/ext/tokyotyrant-1.1.39/ext/mapreduce.lua +57 -0
  280. data/ext/tokyotyrant-1.1.39/ext/queue.lua +55 -0
  281. data/ext/tokyotyrant-1.1.39/ext/senatus.lua +532 -0
  282. data/ext/tokyotyrant-1.1.39/ext/usherette.lua +438 -0
  283. data/ext/tokyotyrant-1.1.39/lab/datechange +56 -0
  284. data/ext/tokyotyrant-1.1.39/lab/diffcheck +45 -0
  285. data/ext/tokyotyrant-1.1.39/lab/fibonacci.lua +20 -0
  286. data/ext/tokyotyrant-1.1.39/lab/footprint.lua +67 -0
  287. data/ext/tokyotyrant-1.1.39/lab/highlow.lua +88 -0
  288. data/ext/tokyotyrant-1.1.39/lab/killdualmaster +12 -0
  289. data/ext/tokyotyrant-1.1.39/lab/rundualmaster +38 -0
  290. data/ext/tokyotyrant-1.1.39/lab/stepcount +26 -0
  291. data/ext/tokyotyrant-1.1.39/lab/tabcheck +43 -0
  292. data/ext/tokyotyrant-1.1.39/lab/ushrtregister.pl +55 -0
  293. data/ext/tokyotyrant-1.1.39/lab/widthcheck +57 -0
  294. data/ext/tokyotyrant-1.1.39/man/htmltoman +100 -0
  295. data/ext/tokyotyrant-1.1.39/man/tcrdb.3 +1309 -0
  296. data/ext/tokyotyrant-1.1.39/man/tcrmgr.1 +164 -0
  297. data/ext/tokyotyrant-1.1.39/man/tcrmttest.1 +55 -0
  298. data/ext/tokyotyrant-1.1.39/man/tcrtest.1 +89 -0
  299. data/ext/tokyotyrant-1.1.39/man/tculog.3 +15 -0
  300. data/ext/tokyotyrant-1.1.39/man/ttservctl.8 +37 -0
  301. data/ext/tokyotyrant-1.1.39/man/ttserver.1 +84 -0
  302. data/ext/tokyotyrant-1.1.39/man/ttulmgr.1 +40 -0
  303. data/ext/tokyotyrant-1.1.39/man/ttultest.1 +16 -0
  304. data/ext/tokyotyrant-1.1.39/man/ttutil.3 +14 -0
  305. data/ext/tokyotyrant-1.1.39/myconf.c +169 -0
  306. data/ext/tokyotyrant-1.1.39/myconf.h +408 -0
  307. data/ext/tokyotyrant-1.1.39/scrext.c +2394 -0
  308. data/ext/tokyotyrant-1.1.39/scrext.h +96 -0
  309. data/ext/tokyotyrant-1.1.39/tcrdb.c +2637 -0
  310. data/ext/tokyotyrant-1.1.39/tcrdb.h +801 -0
  311. data/ext/tokyotyrant-1.1.39/tcrmgr.c +1559 -0
  312. data/ext/tokyotyrant-1.1.39/tcrmttest.c +915 -0
  313. data/ext/tokyotyrant-1.1.39/tcrtest.c +1542 -0
  314. data/ext/tokyotyrant-1.1.39/tculog.c +1211 -0
  315. data/ext/tokyotyrant-1.1.39/tculog.h +392 -0
  316. data/ext/tokyotyrant-1.1.39/tokyotyrant.idl +143 -0
  317. data/ext/tokyotyrant-1.1.39/tokyotyrant.pc.in +14 -0
  318. data/ext/tokyotyrant-1.1.39/ttservctl +163 -0
  319. data/ext/tokyotyrant-1.1.39/ttserver.c +3583 -0
  320. data/ext/tokyotyrant-1.1.39/ttskeldir.c +141 -0
  321. data/ext/tokyotyrant-1.1.39/ttskelmock.c +64 -0
  322. data/ext/tokyotyrant-1.1.39/ttskelnull.c +79 -0
  323. data/ext/tokyotyrant-1.1.39/ttskelproxy.c +74 -0
  324. data/ext/tokyotyrant-1.1.39/ttulmgr.c +266 -0
  325. data/ext/tokyotyrant-1.1.39/ttultest.c +371 -0
  326. data/ext/tokyotyrant-1.1.39/ttutil.c +1510 -0
  327. data/ext/tokyotyrant-1.1.39/ttutil.h +494 -0
  328. data/lib/tokyo_tyrant/balancer.rb +189 -0
  329. data/spec/ext.lua +4 -0
  330. data/spec/plu_db.rb +538 -0
  331. data/spec/spec.rb +1 -0
  332. data/spec/spec_base.rb +17 -0
  333. data/spec/start_tyrants.sh +36 -0
  334. data/spec/stop_tyrants.sh +9 -0
  335. data/spec/tokyo_tyrant_balancer_db_spec.rb +160 -0
  336. data/spec/tokyo_tyrant_balancer_table_spec.rb +177 -0
  337. data/spec/tokyo_tyrant_query_spec.rb +159 -0
  338. data/spec/tokyo_tyrant_spec.rb +254 -0
  339. data/spec/tokyo_tyrant_table_spec.rb +301 -0
  340. metadata +402 -0
@@ -0,0 +1,2746 @@
1
+ /*************************************************************************************************
2
+ * The fixed-length database API of Tokyo Cabinet
3
+ * Copyright (C) 2006-2009 Mikio Hirabayashi
4
+ * This file is part of Tokyo Cabinet.
5
+ * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of
6
+ * the GNU Lesser General Public License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope
8
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10
+ * License for more details.
11
+ * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12
+ * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13
+ * Boston, MA 02111-1307 USA.
14
+ *************************************************************************************************/
15
+
16
+
17
+ #include "tcutil.h"
18
+ #include "tcfdb.h"
19
+ #include "myconf.h"
20
+
21
+ #define FDBFILEMODE 00644 // permission of created files
22
+ #define FDBIOBUFSIZ 8192 // size of an I/O buffer
23
+
24
+ #define FDBMAGICDATA "ToKyO CaBiNeT" // magic data for identification
25
+ #define FDBHEADSIZ 256 // size of the reagion of the header
26
+ #define FDBTYPEOFF 32 // offset of the region for the database type
27
+ #define FDBFLAGSOFF 33 // offset of the region for the additional flags
28
+ #define FDBRNUMOFF 48 // offset of the region for the record number
29
+ #define FDBFSIZOFF 56 // offset of the region for the file size
30
+ #define FDBWIDTHOFF 64 // offset of the region for the record width
31
+ #define FDBLIMSIZOFF 72 // offset of the region for the limit size
32
+ #define FDBMINOFF 80 // offset of the region for the minimum ID offset
33
+ #define FDBMAXOFF 88 // offset of the region for the maximum ID offset
34
+ #define FDBOPAQUEOFF 128 // offset of the region for the opaque field
35
+
36
+ #define FDBDEFWIDTH 255 // default value width
37
+ #define FDBDEFLIMSIZ (256LL<<20) // default limit size
38
+ #define FDBRMTXNUM 127 // number of record mutexes
39
+ #define FDBTRUNCALW 256 // number of record for truncate allowance
40
+ #define FDBIDARYUNIT 2048 // size of ID array allocation unit
41
+ #define FDBWALSUFFIX "wal" // suffix of write ahead logging file
42
+
43
+ enum { // enumeration for duplication behavior
44
+ FDBPDOVER, // overwrite an existing value
45
+ FDBPDKEEP, // keep the existing value
46
+ FDBPDCAT, // concatenate values
47
+ FDBPDADDINT, // add an integer
48
+ FDBPDADDDBL, // add a real number
49
+ FDBPDPROC // process by a callback function
50
+ };
51
+
52
+ typedef struct { // type of structure for a duplication callback
53
+ TCPDPROC proc; // function pointer
54
+ void *op; // opaque pointer
55
+ } FDBPDPROCOP;
56
+
57
+
58
+ /* private macros */
59
+ #define FDBLOCKMETHOD(TC_fdb, TC_wr) \
60
+ ((TC_fdb)->mmtx ? tcfdblockmethod((TC_fdb), (TC_wr)) : true)
61
+ #define FDBUNLOCKMETHOD(TC_fdb) \
62
+ ((TC_fdb)->mmtx ? tcfdbunlockmethod(TC_fdb) : true)
63
+ #define FDBLOCKATTR(TC_fdb) \
64
+ ((TC_fdb)->mmtx ? tcfdblockattr(TC_fdb) : true)
65
+ #define FDBUNLOCKATTR(TC_fdb) \
66
+ ((TC_fdb)->mmtx ? tcfdbunlockattr(TC_fdb) : true)
67
+ #define FDBLOCKRECORD(TC_fdb, TC_wr, TC_id) \
68
+ ((TC_fdb)->mmtx ? tcfdblockrecord((TC_fdb), (TC_wr), (TC_id)) : true)
69
+ #define FDBUNLOCKRECORD(TC_fdb, TC_id) \
70
+ ((TC_fdb)->mmtx ? tcfdbunlockrecord((TC_fdb), (TC_id)) : true)
71
+ #define FDBLOCKALLRECORDS(TC_fdb, TC_wr) \
72
+ ((TC_fdb)->mmtx ? tcfdblockallrecords((TC_fdb), (TC_wr)) : true)
73
+ #define FDBUNLOCKALLRECORDS(TC_fdb) \
74
+ ((TC_fdb)->mmtx ? tcfdbunlockallrecords(TC_fdb) : true)
75
+ #define FDBLOCKWAL(TC_fdb) \
76
+ ((TC_fdb)->mmtx ? tcfdblockwal(TC_fdb) : true)
77
+ #define FDBUNLOCKWAL(TC_fdb) \
78
+ ((TC_fdb)->mmtx ? tcfdbunlockwal(TC_fdb) : true)
79
+ #define FDBTHREADYIELD(TC_fdb) \
80
+ do { if((TC_fdb)->mmtx) sched_yield(); } while(false)
81
+
82
+
83
+ /* private function prototypes */
84
+ static void tcfdbdumpmeta(TCFDB *fdb, char *hbuf);
85
+ static void tcfdbloadmeta(TCFDB *fdb, const char *hbuf);
86
+ static void tcfdbclear(TCFDB *fdb);
87
+ static void tcfdbsetflag(TCFDB *fdb, int flag, bool sign);
88
+ static bool tcfdbwalinit(TCFDB *fdb);
89
+ static bool tcfdbwalwrite(TCFDB *fdb, uint64_t off, int64_t size);
90
+ static int tcfdbwalrestore(TCFDB *fdb, const char *path);
91
+ static bool tcfdbwalremove(TCFDB *fdb, const char *path);
92
+ static bool tcfdbopenimpl(TCFDB *fdb, const char *path, int omode);
93
+ static bool tcfdbcloseimpl(TCFDB *fdb);
94
+ static int64_t tcfdbprevid(TCFDB *fdb, int64_t id);
95
+ static int64_t tcfdbnextid(TCFDB *fdb, int64_t id);
96
+ static bool tcfdbputimpl(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, int dmode);
97
+ static bool tcfdboutimpl(TCFDB *fdb, int64_t id);
98
+ static const void *tcfdbgetimpl(TCFDB *fdb, int64_t id, int *sp);
99
+ static bool tcfdbiterinitimpl(TCFDB *fdb);
100
+ static uint64_t tcfdbiternextimpl(TCFDB *fdb);
101
+ static uint64_t *tcfdbrangeimpl(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np);
102
+ static bool tcfdboptimizeimpl(TCFDB *fdb, int32_t width, int64_t limsiz);
103
+ static bool tcfdbvanishimpl(TCFDB *fdb);
104
+ static bool tcfdbcopyimpl(TCFDB *fdb, const char *path);
105
+ static bool tcfdbiterjumpimpl(TCFDB *fdb, int64_t id);
106
+ static bool tcfdbforeachimpl(TCFDB *fdb, TCITER iter, void *op);
107
+ static bool tcfdblockmethod(TCFDB *fdb, bool wr);
108
+ static bool tcfdbunlockmethod(TCFDB *fdb);
109
+ static bool tcfdblockattr(TCFDB *fdb);
110
+ static bool tcfdbunlockattr(TCFDB *fdb);
111
+ static bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id);
112
+ static bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id);
113
+ static bool tcfdblockallrecords(TCFDB *fdb, bool wr);
114
+ static bool tcfdbunlockallrecords(TCFDB *fdb);
115
+ static bool tcfdblockwal(TCFDB *fdb);
116
+ static bool tcfdbunlockwal(TCFDB *fdb);
117
+
118
+
119
+ /* debugging function prototypes */
120
+ void tcfdbprintmeta(TCFDB *fdb);
121
+
122
+
123
+
124
+ /*************************************************************************************************
125
+ * API
126
+ *************************************************************************************************/
127
+
128
+
129
+ /* Get the message string corresponding to an error code. */
130
+ const char *tcfdberrmsg(int ecode){
131
+ return tcerrmsg(ecode);
132
+ }
133
+
134
+
135
+ /* Create a fixed-length database object. */
136
+ TCFDB *tcfdbnew(void){
137
+ TCFDB *fdb;
138
+ TCMALLOC(fdb, sizeof(*fdb));
139
+ tcfdbclear(fdb);
140
+ return fdb;
141
+ }
142
+
143
+
144
+ /* Delete a fixed-length database object. */
145
+ void tcfdbdel(TCFDB *fdb){
146
+ assert(fdb);
147
+ if(fdb->fd >= 0) tcfdbclose(fdb);
148
+ if(fdb->mmtx){
149
+ pthread_key_delete(*(pthread_key_t *)fdb->eckey);
150
+ pthread_mutex_destroy(fdb->wmtx);
151
+ pthread_mutex_destroy(fdb->tmtx);
152
+ for(int i = FDBRMTXNUM - 1; i >= 0; i--){
153
+ pthread_rwlock_destroy((pthread_rwlock_t *)fdb->rmtxs + i);
154
+ }
155
+ pthread_mutex_destroy(fdb->amtx);
156
+ pthread_rwlock_destroy(fdb->mmtx);
157
+ TCFREE(fdb->eckey);
158
+ TCFREE(fdb->wmtx);
159
+ TCFREE(fdb->tmtx);
160
+ TCFREE(fdb->rmtxs);
161
+ TCFREE(fdb->amtx);
162
+ TCFREE(fdb->mmtx);
163
+ }
164
+ TCFREE(fdb);
165
+ }
166
+
167
+
168
+ /* Get the last happened error code of a fixed-length database object. */
169
+ int tcfdbecode(TCFDB *fdb){
170
+ assert(fdb);
171
+ return fdb->mmtx ?
172
+ (int)(intptr_t)pthread_getspecific(*(pthread_key_t *)fdb->eckey) : fdb->ecode;
173
+ }
174
+
175
+
176
+ /* Set mutual exclusion control of a fixed-length database object for threading. */
177
+ bool tcfdbsetmutex(TCFDB *fdb){
178
+ assert(fdb);
179
+ if(!TCUSEPTHREAD) return true;
180
+ if(fdb->mmtx || fdb->fd >= 0){
181
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
182
+ return false;
183
+ }
184
+ TCMALLOC(fdb->mmtx, sizeof(pthread_rwlock_t));
185
+ TCMALLOC(fdb->amtx, sizeof(pthread_mutex_t));
186
+ TCMALLOC(fdb->rmtxs, sizeof(pthread_rwlock_t) * FDBRMTXNUM);
187
+ TCMALLOC(fdb->tmtx, sizeof(pthread_mutex_t));
188
+ TCMALLOC(fdb->wmtx, sizeof(pthread_mutex_t));
189
+ TCMALLOC(fdb->eckey, sizeof(pthread_key_t));
190
+ bool err = false;
191
+ if(pthread_rwlock_init(fdb->mmtx, NULL) != 0) err = true;
192
+ if(pthread_mutex_init(fdb->amtx, NULL) != 0) err = true;
193
+ for(int i = 0; i < FDBRMTXNUM; i++){
194
+ if(pthread_rwlock_init((pthread_rwlock_t *)fdb->rmtxs + i, NULL) != 0) err = true;
195
+ }
196
+ if(pthread_mutex_init(fdb->tmtx, NULL) != 0) err = true;
197
+ if(pthread_mutex_init(fdb->wmtx, NULL) != 0) err = true;
198
+ if(pthread_key_create(fdb->eckey, NULL) != 0) err = true;
199
+ if(err){
200
+ TCFREE(fdb->eckey);
201
+ TCFREE(fdb->wmtx);
202
+ TCFREE(fdb->tmtx);
203
+ TCFREE(fdb->rmtxs);
204
+ TCFREE(fdb->amtx);
205
+ TCFREE(fdb->mmtx);
206
+ fdb->eckey = NULL;
207
+ fdb->wmtx = NULL;
208
+ fdb->tmtx = NULL;
209
+ fdb->rmtxs = NULL;
210
+ fdb->amtx = NULL;
211
+ fdb->mmtx = NULL;
212
+ return false;
213
+ }
214
+ return true;
215
+ }
216
+
217
+
218
+ /* Set the tuning parameters of a fixed-length database object. */
219
+ bool tcfdbtune(TCFDB *fdb, int32_t width, int64_t limsiz){
220
+ assert(fdb);
221
+ if(fdb->fd >= 0){
222
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
223
+ return false;
224
+ }
225
+ fdb->width = (width > 0) ? width : FDBDEFWIDTH;
226
+ fdb->limsiz = (limsiz > 0) ? limsiz : FDBDEFLIMSIZ;
227
+ if(fdb->limsiz < FDBHEADSIZ + fdb->width + sizeof(uint32_t))
228
+ fdb->limsiz = FDBHEADSIZ + fdb->width + sizeof(uint32_t);
229
+ fdb->limsiz = tcpagealign(fdb->limsiz);
230
+ return true;
231
+ }
232
+
233
+
234
+ /* Open a database file and connect a fixed-length database object. */
235
+ bool tcfdbopen(TCFDB *fdb, const char *path, int omode){
236
+ assert(fdb && path);
237
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
238
+ if(fdb->fd >= 0){
239
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
240
+ FDBUNLOCKMETHOD(fdb);
241
+ return false;
242
+ }
243
+ char *rpath = tcrealpath(path);
244
+ if(!rpath){
245
+ int ecode = TCEOPEN;
246
+ switch(errno){
247
+ case EACCES: ecode = TCENOPERM; break;
248
+ case ENOENT: ecode = TCENOFILE; break;
249
+ case ENOTDIR: ecode = TCENOFILE; break;
250
+ }
251
+ tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__);
252
+ FDBUNLOCKMETHOD(fdb);
253
+ return false;
254
+ }
255
+ if(!tcpathlock(rpath)){
256
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
257
+ TCFREE(rpath);
258
+ FDBUNLOCKMETHOD(fdb);
259
+ return false;
260
+ }
261
+ bool rv = tcfdbopenimpl(fdb, path, omode);
262
+ if(rv){
263
+ fdb->rpath = rpath;
264
+ } else {
265
+ tcpathunlock(rpath);
266
+ TCFREE(rpath);
267
+ }
268
+ FDBUNLOCKMETHOD(fdb);
269
+ return rv;
270
+ }
271
+
272
+
273
+ /* Close a fixed-length database object. */
274
+ bool tcfdbclose(TCFDB *fdb){
275
+ assert(fdb);
276
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
277
+ if(fdb->fd < 0){
278
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
279
+ FDBUNLOCKMETHOD(fdb);
280
+ return false;
281
+ }
282
+ bool rv = tcfdbcloseimpl(fdb);
283
+ tcpathunlock(fdb->rpath);
284
+ TCFREE(fdb->rpath);
285
+ fdb->rpath = NULL;
286
+ FDBUNLOCKMETHOD(fdb);
287
+ return rv;
288
+ }
289
+
290
+
291
+ /* Store a record into a fixed-length database object. */
292
+ bool tcfdbput(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){
293
+ assert(fdb && vbuf && vsiz >= 0);
294
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return false;
295
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
296
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
297
+ FDBUNLOCKMETHOD(fdb);
298
+ return false;
299
+ }
300
+ if(id == FDBIDMIN){
301
+ id = fdb->min;
302
+ } else if(id == FDBIDPREV){
303
+ id = fdb->min - 1;
304
+ } else if(id == FDBIDMAX){
305
+ id = fdb->max;
306
+ } else if(id == FDBIDNEXT){
307
+ id = fdb->max + 1;
308
+ }
309
+ if(id < 1 || id > fdb->limid){
310
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
311
+ FDBUNLOCKMETHOD(fdb);
312
+ return false;
313
+ }
314
+ if(!FDBLOCKRECORD(fdb, true, id)){
315
+ FDBUNLOCKMETHOD(fdb);
316
+ return false;
317
+ }
318
+ bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDOVER);
319
+ FDBUNLOCKRECORD(fdb, id);
320
+ FDBUNLOCKMETHOD(fdb);
321
+ return rv;
322
+ }
323
+
324
+
325
+ /* Store a record with a decimal key into a fixed-length database object. */
326
+ bool tcfdbput2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
327
+ assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
328
+ return tcfdbput(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz);
329
+ }
330
+
331
+
332
+ /* Store a string record with a decimal key into a fixed-length database object. */
333
+ bool tcfdbput3(TCFDB *fdb, const char *kstr, const void *vstr){
334
+ assert(fdb && kstr && vstr);
335
+ return tcfdbput(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr));
336
+ }
337
+
338
+
339
+ /* Store a new record into a fixed-length database object. */
340
+ bool tcfdbputkeep(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){
341
+ assert(fdb && vbuf && vsiz >= 0);
342
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return false;
343
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
344
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
345
+ FDBUNLOCKMETHOD(fdb);
346
+ return false;
347
+ }
348
+ if(id == FDBIDMIN){
349
+ id = fdb->min;
350
+ } else if(id == FDBIDPREV){
351
+ id = fdb->min - 1;
352
+ } else if(id == FDBIDMAX){
353
+ id = fdb->max;
354
+ } else if(id == FDBIDNEXT){
355
+ id = fdb->max + 1;
356
+ }
357
+ if(id < 1 || id > fdb->limid){
358
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
359
+ FDBUNLOCKMETHOD(fdb);
360
+ return false;
361
+ }
362
+ if(!FDBLOCKRECORD(fdb, true, id)){
363
+ FDBUNLOCKMETHOD(fdb);
364
+ return false;
365
+ }
366
+ bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDKEEP);
367
+ FDBUNLOCKRECORD(fdb, id);
368
+ FDBUNLOCKMETHOD(fdb);
369
+ return rv;
370
+ }
371
+
372
+
373
+ /* Store a new record with a decimal key into a fixed-length database object. */
374
+ bool tcfdbputkeep2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
375
+ assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
376
+ return tcfdbputkeep(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz);
377
+ }
378
+
379
+
380
+ /* Store a new string record with a decimal key into a fixed-length database object. */
381
+ bool tcfdbputkeep3(TCFDB *fdb, const char *kstr, const void *vstr){
382
+ assert(fdb && kstr && vstr);
383
+ return tcfdbputkeep(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr));
384
+ }
385
+
386
+
387
+ /* Concatenate a value at the end of the existing record in a fixed-length database object. */
388
+ bool tcfdbputcat(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz){
389
+ assert(fdb && vbuf && vsiz >= 0);
390
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return false;
391
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
392
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
393
+ FDBUNLOCKMETHOD(fdb);
394
+ return false;
395
+ }
396
+ if(id == FDBIDMIN){
397
+ id = fdb->min;
398
+ } else if(id == FDBIDPREV){
399
+ id = fdb->min - 1;
400
+ } else if(id == FDBIDMAX){
401
+ id = fdb->max;
402
+ } else if(id == FDBIDNEXT){
403
+ id = fdb->max + 1;
404
+ }
405
+ if(id < 1 || id > fdb->limid){
406
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
407
+ FDBUNLOCKMETHOD(fdb);
408
+ return false;
409
+ }
410
+ if(!FDBLOCKRECORD(fdb, true, id)){
411
+ FDBUNLOCKMETHOD(fdb);
412
+ return false;
413
+ }
414
+ bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDCAT);
415
+ FDBUNLOCKRECORD(fdb, id);
416
+ FDBUNLOCKMETHOD(fdb);
417
+ return rv;
418
+ }
419
+
420
+
421
+ /* Concatenate a value with a decimal key in a fixed-length database object. */
422
+ bool tcfdbputcat2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
423
+ assert(fdb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
424
+ return tcfdbputcat(fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz);
425
+ }
426
+
427
+
428
+ /* Concatenate a string value with a decimal key in a fixed-length database object. */
429
+ bool tcfdbputcat3(TCFDB *fdb, const char *kstr, const void *vstr){
430
+ assert(fdb && kstr && vstr);
431
+ return tcfdbputcat(fdb, tcfdbkeytoid(kstr, strlen(kstr)), vstr, strlen(vstr));
432
+ }
433
+
434
+
435
+ /* Remove a record of a fixed-length database object. */
436
+ bool tcfdbout(TCFDB *fdb, int64_t id){
437
+ assert(fdb);
438
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
439
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
440
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
441
+ FDBUNLOCKMETHOD(fdb);
442
+ return false;
443
+ }
444
+ if(id == FDBIDMIN){
445
+ id = fdb->min;
446
+ } else if(id == FDBIDMAX){
447
+ id = fdb->max;
448
+ }
449
+ if(id < 1 || id > fdb->limid){
450
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
451
+ FDBUNLOCKMETHOD(fdb);
452
+ return false;
453
+ }
454
+ if(!FDBLOCKRECORD(fdb, true, id)){
455
+ FDBUNLOCKMETHOD(fdb);
456
+ return false;
457
+ }
458
+ bool rv = tcfdboutimpl(fdb, id);
459
+ FDBUNLOCKRECORD(fdb, id);
460
+ FDBUNLOCKMETHOD(fdb);
461
+ return rv;
462
+ }
463
+
464
+
465
+ /* Remove a record with a decimal key of a fixed-length database object. */
466
+ bool tcfdbout2(TCFDB *fdb, const void *kbuf, int ksiz){
467
+ assert(fdb && kbuf && ksiz >= 0);
468
+ return tcfdbout(fdb, tcfdbkeytoid(kbuf, ksiz));
469
+ }
470
+
471
+
472
+ /* Remove a string record with a decimal key of a fixed-length database object. */
473
+ bool tcfdbout3(TCFDB *fdb, const char *kstr){
474
+ assert(fdb && kstr);
475
+ return tcfdbout(fdb, tcfdbkeytoid(kstr, strlen(kstr)));
476
+ }
477
+
478
+
479
+ /* Retrieve a record in a fixed-length database object. */
480
+ void *tcfdbget(TCFDB *fdb, int64_t id, int *sp){
481
+ assert(fdb && sp);
482
+ if(!FDBLOCKMETHOD(fdb, false)) return false;
483
+ if(fdb->fd < 0){
484
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
485
+ FDBUNLOCKMETHOD(fdb);
486
+ return false;
487
+ }
488
+ if(id == FDBIDMIN){
489
+ id = fdb->min;
490
+ } else if(id == FDBIDMAX){
491
+ id = fdb->max;
492
+ }
493
+ if(id < 1 || id > fdb->limid){
494
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
495
+ FDBUNLOCKMETHOD(fdb);
496
+ return false;
497
+ }
498
+ if(!FDBLOCKRECORD(fdb, false, id)){
499
+ FDBUNLOCKMETHOD(fdb);
500
+ return false;
501
+ }
502
+ const void *vbuf = tcfdbgetimpl(fdb, id, sp);
503
+ char *rv = vbuf ? tcmemdup(vbuf, *sp) : NULL;
504
+ FDBUNLOCKRECORD(fdb, id);
505
+ FDBUNLOCKMETHOD(fdb);
506
+ return rv;
507
+ }
508
+
509
+
510
+ /* Retrieve a record with a decimal key in a fixed-length database object. */
511
+ void *tcfdbget2(TCFDB *fdb, const void *kbuf, int ksiz, int *sp){
512
+ assert(fdb && kbuf && ksiz >= 0 && sp);
513
+ return tcfdbget(fdb, tcfdbkeytoid(kbuf, ksiz), sp);
514
+ }
515
+
516
+
517
+ /* Retrieve a string record with a decimal key in a fixed-length database object. */
518
+ char *tcfdbget3(TCFDB *fdb, const char *kstr){
519
+ assert(fdb && kstr);
520
+ int vsiz;
521
+ return tcfdbget(fdb, tcfdbkeytoid(kstr, strlen(kstr)), &vsiz);
522
+ }
523
+
524
+
525
+ /* Retrieve a record in a fixed-length database object and write the value into a buffer. */
526
+ int tcfdbget4(TCFDB *fdb, int64_t id, void *vbuf, int max){
527
+ assert(fdb && vbuf && max >= 0);
528
+ if(!FDBLOCKMETHOD(fdb, false)) return false;
529
+ if(fdb->fd < 0){
530
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
531
+ FDBUNLOCKMETHOD(fdb);
532
+ return false;
533
+ }
534
+ if(id == FDBIDMIN){
535
+ id = fdb->min;
536
+ } else if(id == FDBIDMAX){
537
+ id = fdb->max;
538
+ }
539
+ if(id < 1 || id > fdb->limid){
540
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
541
+ FDBUNLOCKMETHOD(fdb);
542
+ return false;
543
+ }
544
+ if(!FDBLOCKRECORD(fdb, false, id)){
545
+ FDBUNLOCKMETHOD(fdb);
546
+ return false;
547
+ }
548
+ int vsiz;
549
+ const void *rbuf = tcfdbgetimpl(fdb, id, &vsiz);
550
+ if(rbuf){
551
+ if(vsiz > max) vsiz = max;
552
+ memcpy(vbuf, rbuf, vsiz);
553
+ } else {
554
+ vsiz = -1;
555
+ }
556
+ FDBUNLOCKRECORD(fdb, id);
557
+ FDBUNLOCKMETHOD(fdb);
558
+ return vsiz;
559
+ }
560
+
561
+
562
+ /* Get the size of the value of a record in a fixed-length database object. */
563
+ int tcfdbvsiz(TCFDB *fdb, int64_t id){
564
+ assert(fdb);
565
+ if(!FDBLOCKMETHOD(fdb, false)) return false;
566
+ if(fdb->fd < 0){
567
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
568
+ FDBUNLOCKMETHOD(fdb);
569
+ return false;
570
+ }
571
+ if(id == FDBIDMIN){
572
+ id = fdb->min;
573
+ } else if(id == FDBIDMAX){
574
+ id = fdb->max;
575
+ }
576
+ if(id < 1 || id > fdb->limid){
577
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
578
+ FDBUNLOCKMETHOD(fdb);
579
+ return false;
580
+ }
581
+ if(!FDBLOCKRECORD(fdb, false, id)){
582
+ FDBUNLOCKMETHOD(fdb);
583
+ return false;
584
+ }
585
+ int vsiz;
586
+ const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz);
587
+ if(!vbuf) vsiz = -1;
588
+ FDBUNLOCKRECORD(fdb, id);
589
+ FDBUNLOCKMETHOD(fdb);
590
+ return vsiz;
591
+ }
592
+
593
+
594
+ /* Get the size of the value with a decimal key in a fixed-length database object. */
595
+ int tcfdbvsiz2(TCFDB *fdb, const void *kbuf, int ksiz){
596
+ assert(fdb && kbuf && ksiz >= 0);
597
+ return tcfdbvsiz(fdb, tcfdbkeytoid(kbuf, ksiz));
598
+ }
599
+
600
+
601
+ /* Get the size of the string value with a decimal key in a fixed-length database object. */
602
+ int tcfdbvsiz3(TCFDB *fdb, const char *kstr){
603
+ assert(fdb && kstr);
604
+ return tcfdbvsiz(fdb, tcfdbkeytoid(kstr, strlen(kstr)));
605
+ }
606
+
607
+
608
+ /* Initialize the iterator of a fixed-length database object. */
609
+ bool tcfdbiterinit(TCFDB *fdb){
610
+ assert(fdb);
611
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
612
+ if(fdb->fd < 0){
613
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
614
+ FDBUNLOCKMETHOD(fdb);
615
+ return false;
616
+ }
617
+ bool rv = tcfdbiterinitimpl(fdb);
618
+ FDBUNLOCKMETHOD(fdb);
619
+ return rv;
620
+ }
621
+
622
+
623
+ /* Get the next ID number of the iterator of a fixed-length database object. */
624
+ uint64_t tcfdbiternext(TCFDB *fdb){
625
+ assert(fdb);
626
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
627
+ if(fdb->fd < 0){
628
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
629
+ FDBUNLOCKMETHOD(fdb);
630
+ return false;
631
+ }
632
+ uint64_t rv = tcfdbiternextimpl(fdb);
633
+ FDBUNLOCKMETHOD(fdb);
634
+ return rv;
635
+ }
636
+
637
+
638
+ /* Get the next decimay key of the iterator of a fixed-length database object. */
639
+ void *tcfdbiternext2(TCFDB *fdb, int *sp){
640
+ assert(fdb && sp);
641
+ uint64_t id = tcfdbiternextimpl(fdb);
642
+ if(id < 1) return NULL;
643
+ char kbuf[TCNUMBUFSIZ];
644
+ int ksiz = sprintf(kbuf, "%llu", (unsigned long long)id);
645
+ *sp = ksiz;
646
+ return tcmemdup(kbuf, ksiz);
647
+ }
648
+
649
+
650
+ /* Get the next decimay key string of the iterator of a fixed-length database object. */
651
+ char *tcfdbiternext3(TCFDB *fdb){
652
+ assert(fdb);
653
+ int ksiz;
654
+ return tcfdbiternext2(fdb, &ksiz);
655
+ }
656
+
657
+
658
+ /* Get range matching decimal keys in a fixed-length database object. */
659
+ uint64_t *tcfdbrange(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np){
660
+ assert(fdb && np);
661
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
662
+ if(fdb->fd < 0){
663
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
664
+ FDBUNLOCKMETHOD(fdb);
665
+ *np = 0;
666
+ return tcmalloc(1);
667
+ }
668
+ if(lower == FDBIDMIN) lower = fdb->min;
669
+ if(upper == FDBIDMAX) upper = fdb->max;
670
+ if(lower < 1 || lower > fdb->limid || upper < 1 || upper > fdb->limid){
671
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
672
+ FDBUNLOCKMETHOD(fdb);
673
+ *np = 0;
674
+ return tcmalloc(1);
675
+ }
676
+ uint64_t *rv = tcfdbrangeimpl(fdb, lower, upper, max, np);
677
+ FDBUNLOCKMETHOD(fdb);
678
+ return rv;
679
+ }
680
+
681
+
682
+ /* Get range matching decimal keys in a fixed-length database object. */
683
+ TCLIST *tcfdbrange2(TCFDB *fdb, const void *lbuf, int lsiz, const void *ubuf, int usiz, int max){
684
+ assert(fdb && lbuf && lsiz >= 0 && ubuf && usiz >= 0);
685
+ int num;
686
+ uint64_t *ids = tcfdbrange(fdb, tcfdbkeytoid(lbuf, lsiz), tcfdbkeytoid(ubuf, usiz), max, &num);
687
+ TCLIST *keys = tclistnew2(num);
688
+ for(int i = 0; i < num; i++){
689
+ char kbuf[TCNUMBUFSIZ];
690
+ int ksiz = sprintf(kbuf, "%llu", (unsigned long long)ids[i]);
691
+ TCLISTPUSH(keys, kbuf, ksiz);
692
+ }
693
+ TCFREE(ids);
694
+ return keys;
695
+ }
696
+
697
+
698
+ /* Get range matching decimal keys with strings in a fixed-length database object. */
699
+ TCLIST *tcfdbrange3(TCFDB *fdb, const char *lstr, const char *ustr, int max){
700
+ assert(fdb && lstr && ustr);
701
+ return tcfdbrange2(fdb, lstr, strlen(lstr), ustr, strlen(ustr), max);
702
+ }
703
+
704
+
705
+ /* Get keys with an interval notation in a fixed-length database object. */
706
+ TCLIST *tcfdbrange4(TCFDB *fdb, const void *ibuf, int isiz, int max){
707
+ assert(fdb && ibuf && isiz >= 0);
708
+ char *expr;
709
+ TCMEMDUP(expr, ibuf, isiz);
710
+ char *pv = expr;
711
+ while(*pv > '\0' && *pv <= ' '){
712
+ pv++;
713
+ }
714
+ bool linc = false;
715
+ if(*pv == '['){
716
+ linc = true;
717
+ } else if(*pv != '('){
718
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
719
+ TCFREE(expr);
720
+ return tclistnew();
721
+ }
722
+ pv++;
723
+ char *sep = strchr(pv, ',');
724
+ if(!sep){
725
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
726
+ TCFREE(expr);
727
+ return tclistnew();
728
+ }
729
+ *sep = '\0';
730
+ tcstrtrim(pv);
731
+ int64_t lower = tcfdbkeytoid(pv, strlen(pv));
732
+ pv = sep + 1;
733
+ bool uinc = false;
734
+ if((sep = strchr(pv, ']')) != NULL){
735
+ uinc = true;
736
+ *sep = '\0';
737
+ } else if((sep = strchr(pv, ')')) != NULL){
738
+ *sep = '\0';
739
+ } else {
740
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
741
+ TCFREE(expr);
742
+ return tclistnew();
743
+ }
744
+ tcstrtrim(pv);
745
+ int64_t upper = tcfdbkeytoid(pv, strlen(pv));
746
+ if(lower == FDBIDMIN){
747
+ lower = fdb->min;
748
+ } else if(lower == FDBIDPREV){
749
+ lower = fdb->min - 1;
750
+ } else if(lower == FDBIDMAX){
751
+ lower = fdb->max;
752
+ } else if(lower == FDBIDNEXT){
753
+ lower = fdb->max + 1;
754
+ }
755
+ if(!linc) lower++;
756
+ if(upper == FDBIDMIN){
757
+ upper = fdb->min;
758
+ } else if(upper == FDBIDPREV){
759
+ upper = fdb->min - 1;
760
+ } else if(upper == FDBIDMAX){
761
+ upper = fdb->max;
762
+ } else if(upper == FDBIDNEXT){
763
+ upper = fdb->max + 1;
764
+ }
765
+ if(!uinc) upper--;
766
+ TCFREE(expr);
767
+ int num;
768
+ uint64_t *ids = tcfdbrange(fdb, lower, upper, max, &num);
769
+ TCLIST *keys = tclistnew2(num);
770
+ for(int i = 0; i < num; i++){
771
+ char kbuf[TCNUMBUFSIZ];
772
+ int ksiz = sprintf(kbuf, "%llu", (unsigned long long)ids[i]);
773
+ TCLISTPUSH(keys, kbuf, ksiz);
774
+ }
775
+ TCFREE(ids);
776
+ return keys;
777
+ }
778
+
779
+
780
+ /* Get keys with an interval notation string in a fixed-length database object. */
781
+ TCLIST *tcfdbrange5(TCFDB *fdb, const void *istr, int max){
782
+ assert(fdb && istr);
783
+ return tcfdbrange4(fdb, istr, strlen(istr), max);
784
+ }
785
+
786
+
787
+ /* Add an integer to a record in a fixed-length database object. */
788
+ int tcfdbaddint(TCFDB *fdb, int64_t id, int num){
789
+ assert(fdb);
790
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return INT_MIN;
791
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
792
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
793
+ FDBUNLOCKMETHOD(fdb);
794
+ return INT_MIN;
795
+ }
796
+ if(id == FDBIDMIN){
797
+ id = fdb->min;
798
+ } else if(id == FDBIDPREV){
799
+ id = fdb->min - 1;
800
+ } else if(id == FDBIDMAX){
801
+ id = fdb->max;
802
+ } else if(id == FDBIDNEXT){
803
+ id = fdb->max + 1;
804
+ }
805
+ if(id < 1 || id > fdb->limid){
806
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
807
+ FDBUNLOCKMETHOD(fdb);
808
+ return INT_MIN;
809
+ }
810
+ if(!FDBLOCKRECORD(fdb, true, id)){
811
+ FDBUNLOCKMETHOD(fdb);
812
+ return INT_MIN;
813
+ }
814
+ bool rv = tcfdbputimpl(fdb, id, (char *)&num, sizeof(num), FDBPDADDINT);
815
+ FDBUNLOCKRECORD(fdb, id);
816
+ FDBUNLOCKMETHOD(fdb);
817
+ return rv ? num : INT_MIN;
818
+ }
819
+
820
+
821
+ /* Add a real number to a record in a fixed-length database object. */
822
+ double tcfdbadddouble(TCFDB *fdb, int64_t id, double num){
823
+ assert(fdb);
824
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return nan("");
825
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
826
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
827
+ FDBUNLOCKMETHOD(fdb);
828
+ return nan("");
829
+ }
830
+ if(id == FDBIDMIN){
831
+ id = fdb->min;
832
+ } else if(id == FDBIDPREV){
833
+ id = fdb->min - 1;
834
+ } else if(id == FDBIDMAX){
835
+ id = fdb->max;
836
+ } else if(id == FDBIDNEXT){
837
+ id = fdb->max + 1;
838
+ }
839
+ if(id < 1 || id > fdb->limid){
840
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
841
+ FDBUNLOCKMETHOD(fdb);
842
+ return nan("");
843
+ }
844
+ if(!FDBLOCKRECORD(fdb, true, id)){
845
+ FDBUNLOCKMETHOD(fdb);
846
+ return nan("");
847
+ }
848
+ bool rv = tcfdbputimpl(fdb, id, (char *)&num, sizeof(num), FDBPDADDDBL);
849
+ FDBUNLOCKRECORD(fdb, id);
850
+ FDBUNLOCKMETHOD(fdb);
851
+ return rv ? num : nan("");
852
+ }
853
+
854
+
855
+ /* Synchronize updated contents of a fixed-length database object with the file and the device. */
856
+ bool tcfdbsync(TCFDB *fdb){
857
+ assert(fdb);
858
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
859
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->tran){
860
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
861
+ FDBUNLOCKMETHOD(fdb);
862
+ return false;
863
+ }
864
+ bool rv = tcfdbmemsync(fdb, true);
865
+ FDBUNLOCKMETHOD(fdb);
866
+ return rv;
867
+ }
868
+
869
+
870
+ /* Optimize the file of a fixed-length database object. */
871
+ bool tcfdboptimize(TCFDB *fdb, int32_t width, int64_t limsiz){
872
+ assert(fdb);
873
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
874
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->tran){
875
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
876
+ FDBUNLOCKMETHOD(fdb);
877
+ return false;
878
+ }
879
+ FDBTHREADYIELD(fdb);
880
+ bool rv = tcfdboptimizeimpl(fdb, width, limsiz);
881
+ FDBUNLOCKMETHOD(fdb);
882
+ return rv;
883
+ }
884
+
885
+
886
+ /* Remove all records of a fixed-length database object. */
887
+ bool tcfdbvanish(TCFDB *fdb){
888
+ assert(fdb);
889
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
890
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->tran){
891
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
892
+ FDBUNLOCKMETHOD(fdb);
893
+ return false;
894
+ }
895
+ FDBTHREADYIELD(fdb);
896
+ bool rv = tcfdbvanishimpl(fdb);
897
+ FDBUNLOCKMETHOD(fdb);
898
+ return rv;
899
+ }
900
+
901
+
902
+ /* Copy the database file of a fixed-length database object. */
903
+ bool tcfdbcopy(TCFDB *fdb, const char *path){
904
+ assert(fdb && path);
905
+ if(!FDBLOCKMETHOD(fdb, false)) return false;
906
+ if(fdb->fd < 0){
907
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
908
+ FDBUNLOCKMETHOD(fdb);
909
+ return false;
910
+ }
911
+ if(!FDBLOCKALLRECORDS(fdb, false)){
912
+ FDBUNLOCKMETHOD(fdb);
913
+ return false;
914
+ }
915
+ FDBTHREADYIELD(fdb);
916
+ bool rv = tcfdbcopyimpl(fdb, path);
917
+ FDBUNLOCKALLRECORDS(fdb);
918
+ FDBUNLOCKMETHOD(fdb);
919
+ return rv;
920
+ }
921
+
922
+
923
+ /* Begin the transaction of a fixed-length database object. */
924
+ bool tcfdbtranbegin(TCFDB *fdb){
925
+ assert(fdb);
926
+ for(double wsec = 1.0 / sysconf(_SC_CLK_TCK); true; wsec *= 2){
927
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
928
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->fatal){
929
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
930
+ FDBUNLOCKMETHOD(fdb);
931
+ return false;
932
+ }
933
+ if(!fdb->tran) break;
934
+ FDBUNLOCKMETHOD(fdb);
935
+ if(wsec > 1.0) wsec = 1.0;
936
+ tcsleep(wsec);
937
+ }
938
+ if(!tcfdbmemsync(fdb, false)){
939
+ FDBUNLOCKMETHOD(fdb);
940
+ return false;
941
+ }
942
+ if((fdb->omode & FDBOTSYNC) && fsync(fdb->fd) == -1){
943
+ tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);
944
+ return false;
945
+ }
946
+ if(fdb->walfd < 0){
947
+ char *tpath = tcsprintf("%s%c%s", fdb->path, MYEXTCHR, FDBWALSUFFIX);
948
+ int walfd = open(tpath, O_RDWR | O_CREAT | O_TRUNC, FDBFILEMODE);
949
+ TCFREE(tpath);
950
+ if(walfd < 0){
951
+ int ecode = TCEOPEN;
952
+ switch(errno){
953
+ case EACCES: ecode = TCENOPERM; break;
954
+ case ENOENT: ecode = TCENOFILE; break;
955
+ case ENOTDIR: ecode = TCENOFILE; break;
956
+ }
957
+ tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__);
958
+ FDBUNLOCKMETHOD(fdb);
959
+ return false;
960
+ }
961
+ fdb->walfd = walfd;
962
+ }
963
+ tcfdbsetflag(fdb, FDBFOPEN, false);
964
+ if(!tcfdbwalinit(fdb)){
965
+ tcfdbsetflag(fdb, FDBFOPEN, true);
966
+ FDBUNLOCKMETHOD(fdb);
967
+ return false;
968
+ }
969
+ tcfdbsetflag(fdb, FDBFOPEN, true);
970
+ fdb->tran = true;
971
+ FDBUNLOCKMETHOD(fdb);
972
+ return true;
973
+ }
974
+
975
+
976
+ /* Commit the transaction of a fixed-length database object. */
977
+ bool tcfdbtrancommit(TCFDB *fdb){
978
+ assert(fdb);
979
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
980
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || fdb->fatal || !fdb->tran){
981
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
982
+ FDBUNLOCKMETHOD(fdb);
983
+ return false;
984
+ }
985
+ bool err = false;
986
+ if(!tcfdbmemsync(fdb, fdb->omode & FDBOTSYNC)) err = true;
987
+ if(!err && ftruncate(fdb->walfd, 0) == -1){
988
+ tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);
989
+ err = true;
990
+ }
991
+ fdb->tran = false;
992
+ FDBUNLOCKMETHOD(fdb);
993
+ return !err;
994
+ }
995
+
996
+
997
+ /* Abort the transaction of a fixed-length database object. */
998
+ bool tcfdbtranabort(TCFDB *fdb){
999
+ assert(fdb);
1000
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
1001
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER) || !fdb->tran){
1002
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1003
+ FDBUNLOCKMETHOD(fdb);
1004
+ return false;
1005
+ }
1006
+ bool err = false;
1007
+ if(!tcfdbmemsync(fdb, false)) err = true;
1008
+ if(!tcfdbwalrestore(fdb, fdb->path)) err = true;
1009
+ char hbuf[FDBHEADSIZ];
1010
+ if(lseek(fdb->fd, 0, SEEK_SET) == -1){
1011
+ tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);
1012
+ err = false;
1013
+ } else if(!tcread(fdb->fd, hbuf, FDBHEADSIZ)){
1014
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1015
+ err = false;
1016
+ } else {
1017
+ tcfdbloadmeta(fdb, hbuf);
1018
+ }
1019
+ fdb->tran = false;
1020
+ FDBUNLOCKMETHOD(fdb);
1021
+ return !err;
1022
+ }
1023
+
1024
+
1025
+ /* Get the file path of a fixed-length database object. */
1026
+ const char *tcfdbpath(TCFDB *fdb){
1027
+ assert(fdb);
1028
+ if(!FDBLOCKMETHOD(fdb, false)) return NULL;
1029
+ if(fdb->fd < 0){
1030
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1031
+ FDBUNLOCKMETHOD(fdb);
1032
+ return NULL;
1033
+ }
1034
+ const char *rv = fdb->path;
1035
+ FDBUNLOCKMETHOD(fdb);
1036
+ return rv;
1037
+ }
1038
+
1039
+
1040
+ /* Get the number of records of a fixed-length database object. */
1041
+ uint64_t tcfdbrnum(TCFDB *fdb){
1042
+ assert(fdb);
1043
+ if(!FDBLOCKMETHOD(fdb, false)) return 0;
1044
+ if(fdb->fd < 0){
1045
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1046
+ FDBUNLOCKMETHOD(fdb);
1047
+ return 0;
1048
+ }
1049
+ uint64_t rv = fdb->rnum;
1050
+ FDBUNLOCKMETHOD(fdb);
1051
+ return rv;
1052
+ }
1053
+
1054
+
1055
+ /* Get the size of the database file of a fixed-length database object. */
1056
+ uint64_t tcfdbfsiz(TCFDB *fdb){
1057
+ assert(fdb);
1058
+ if(!FDBLOCKMETHOD(fdb, false)) return 0;
1059
+ if(fdb->fd < 0){
1060
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1061
+ FDBUNLOCKMETHOD(fdb);
1062
+ return 0;
1063
+ }
1064
+ uint64_t rv = fdb->fsiz;
1065
+ FDBUNLOCKMETHOD(fdb);
1066
+ return rv;
1067
+ }
1068
+
1069
+
1070
+
1071
+ /*************************************************************************************************
1072
+ * features for experts
1073
+ *************************************************************************************************/
1074
+
1075
+
1076
+ /* Set the error code of a fixed-length database object. */
1077
+ void tcfdbsetecode(TCFDB *fdb, int ecode, const char *filename, int line, const char *func){
1078
+ assert(fdb && filename && line >= 1 && func);
1079
+ int myerrno = errno;
1080
+ if(!fdb->fatal){
1081
+ fdb->ecode = ecode;
1082
+ if(fdb->mmtx) pthread_setspecific(*(pthread_key_t *)fdb->eckey, (void *)(intptr_t)ecode);
1083
+ }
1084
+ if(ecode != TCEINVALID && ecode != TCEKEEP && ecode != TCENOREC){
1085
+ fdb->fatal = true;
1086
+ if(fdb->fd >= 0 && (fdb->omode & FDBOWRITER)) tcfdbsetflag(fdb, FDBFFATAL, true);
1087
+ }
1088
+ if(fdb->dbgfd >= 0 && (fdb->dbgfd != UINT16_MAX || fdb->fatal)){
1089
+ int dbgfd = (fdb->dbgfd == UINT16_MAX) ? 1 : fdb->dbgfd;
1090
+ char obuf[FDBIOBUFSIZ];
1091
+ int osiz = sprintf(obuf, "ERROR:%s:%d:%s:%s:%d:%s:%d:%s\n", filename, line, func,
1092
+ fdb->path ? fdb->path : "-", ecode, tcfdberrmsg(ecode),
1093
+ myerrno, strerror(myerrno));
1094
+ tcwrite(dbgfd, obuf, osiz);
1095
+ }
1096
+ }
1097
+
1098
+
1099
+ /* Set the file descriptor for debugging output. */
1100
+ void tcfdbsetdbgfd(TCFDB *fdb, int fd){
1101
+ assert(fdb && fd >= 0);
1102
+ fdb->dbgfd = fd;
1103
+ }
1104
+
1105
+
1106
+ /* Get the file descriptor for debugging output. */
1107
+ int tcfdbdbgfd(TCFDB *fdb){
1108
+ assert(fdb);
1109
+ return fdb->dbgfd;
1110
+ }
1111
+
1112
+
1113
+ /* Check whether mutual exclusion control is set to a fixed-length database object. */
1114
+ bool tcfdbhasmutex(TCFDB *fdb){
1115
+ assert(fdb);
1116
+ return fdb->mmtx != NULL;
1117
+ }
1118
+
1119
+
1120
+ /* Synchronize updating contents on memory of a fixed-length database object. */
1121
+ bool tcfdbmemsync(TCFDB *fdb, bool phys){
1122
+ assert(fdb);
1123
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
1124
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1125
+ return false;
1126
+ }
1127
+ bool err = false;
1128
+ char hbuf[FDBHEADSIZ];
1129
+ tcfdbdumpmeta(fdb, hbuf);
1130
+ memcpy(fdb->map, hbuf, FDBOPAQUEOFF);
1131
+ if(phys){
1132
+ if(msync(fdb->map, fdb->limsiz, MS_SYNC) == -1){
1133
+ tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__);
1134
+ err = true;
1135
+ }
1136
+ if(fsync(fdb->fd) == -1){
1137
+ tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);
1138
+ err = true;
1139
+ }
1140
+ }
1141
+ return !err;
1142
+ }
1143
+
1144
+
1145
+ /* Get the minimum ID number of records of a fixed-length database object. */
1146
+ uint64_t tcfdbmin(TCFDB *fdb){
1147
+ assert(fdb);
1148
+ if(fdb->fd < 0){
1149
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1150
+ return 0;
1151
+ }
1152
+ return fdb->min;
1153
+ }
1154
+
1155
+
1156
+ /* Get the maximum ID number of records of a fixed-length database object. */
1157
+ uint64_t tcfdbmax(TCFDB *fdb){
1158
+ assert(fdb);
1159
+ if(fdb->fd < 0){
1160
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1161
+ return 0;
1162
+ }
1163
+ return fdb->max;
1164
+ }
1165
+
1166
+
1167
+ /* Get the width of the value of each record of a fixed-length database object. */
1168
+ uint32_t tcfdbwidth(TCFDB *fdb){
1169
+ assert(fdb);
1170
+ if(fdb->fd < 0){
1171
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1172
+ return 0;
1173
+ }
1174
+ return fdb->width;
1175
+ }
1176
+
1177
+
1178
+ /* Get the limit file size of a fixed-length database object. */
1179
+ uint64_t tcfdblimsiz(TCFDB *fdb){
1180
+ assert(fdb);
1181
+ if(fdb->fd < 0){
1182
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1183
+ return 0;
1184
+ }
1185
+ return fdb->limsiz;
1186
+ }
1187
+
1188
+
1189
+ /* Get the limit ID number of a fixed-length database object. */
1190
+ uint64_t tcfdblimid(TCFDB *fdb){
1191
+ assert(fdb);
1192
+ if(fdb->fd < 0){
1193
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1194
+ return 0;
1195
+ }
1196
+ return fdb->limid;
1197
+ }
1198
+
1199
+
1200
+ /* Get the inode number of the database file of a fixed-length database object. */
1201
+ uint64_t tcfdbinode(TCFDB *fdb){
1202
+ assert(fdb);
1203
+ if(fdb->fd < 0){
1204
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1205
+ return 0;
1206
+ }
1207
+ return fdb->inode;
1208
+ }
1209
+
1210
+
1211
+ /* Get the modification time of the database file of a fixed-length database object. */
1212
+ time_t tcfdbmtime(TCFDB *fdb){
1213
+ assert(fdb);
1214
+ if(fdb->fd < 0){
1215
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1216
+ return 0;
1217
+ }
1218
+ return fdb->mtime;
1219
+ }
1220
+
1221
+
1222
+ /* Get the connection mode of a fixed-length database object. */
1223
+ int tcfdbomode(TCFDB *fdb){
1224
+ assert(fdb);
1225
+ if(fdb->fd < 0){
1226
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1227
+ return 0;
1228
+ }
1229
+ return fdb->omode;
1230
+ }
1231
+
1232
+
1233
+ /* Get the database type of a fixed-length database object. */
1234
+ uint8_t tcfdbtype(TCFDB *fdb){
1235
+ assert(fdb);
1236
+ if(fdb->fd < 0){
1237
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1238
+ return 0;
1239
+ }
1240
+ return fdb->type;
1241
+ }
1242
+
1243
+
1244
+ /* Get the additional flags of a fixed-length database object. */
1245
+ uint8_t tcfdbflags(TCFDB *fdb){
1246
+ assert(fdb);
1247
+ if(fdb->fd < 0){
1248
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1249
+ return 0;
1250
+ }
1251
+ return fdb->flags;
1252
+ }
1253
+
1254
+
1255
+ /* Get the pointer to the opaque field of a fixed-length database object. */
1256
+ char *tcfdbopaque(TCFDB *fdb){
1257
+ assert(fdb);
1258
+ if(fdb->fd < 0){
1259
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1260
+ return NULL;
1261
+ }
1262
+ return fdb->map + FDBOPAQUEOFF;
1263
+ }
1264
+
1265
+
1266
+ /* Store a record into a fixed-length database object with a duplication handler. */
1267
+ bool tcfdbputproc(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, TCPDPROC proc, void *op){
1268
+ assert(fdb && proc);
1269
+ if(!FDBLOCKMETHOD(fdb, id < 1)) return false;
1270
+ if(fdb->fd < 0 || !(fdb->omode & FDBOWRITER)){
1271
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1272
+ FDBUNLOCKMETHOD(fdb);
1273
+ return false;
1274
+ }
1275
+ if(id == FDBIDMIN){
1276
+ id = fdb->min;
1277
+ } else if(id == FDBIDPREV){
1278
+ id = fdb->min - 1;
1279
+ } else if(id == FDBIDMAX){
1280
+ id = fdb->max;
1281
+ } else if(id == FDBIDNEXT){
1282
+ id = fdb->max + 1;
1283
+ }
1284
+ if(id < 1 || id > fdb->limid){
1285
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1286
+ FDBUNLOCKMETHOD(fdb);
1287
+ return false;
1288
+ }
1289
+ if(!FDBLOCKRECORD(fdb, true, id)){
1290
+ FDBUNLOCKMETHOD(fdb);
1291
+ return false;
1292
+ }
1293
+ FDBPDPROCOP procop;
1294
+ procop.proc = proc;
1295
+ procop.op = op;
1296
+ FDBPDPROCOP *procptr = &procop;
1297
+ tcgeneric_t stack[(FDBDEFWIDTH+TCNUMBUFSIZ)/sizeof(tcgeneric_t)+1];
1298
+ char *rbuf;
1299
+ if(vbuf){
1300
+ if(vsiz <= sizeof(stack) - sizeof(procptr)){
1301
+ rbuf = (char *)stack;
1302
+ } else {
1303
+ TCMALLOC(rbuf, vsiz + sizeof(procptr));
1304
+ }
1305
+ char *wp = rbuf;
1306
+ memcpy(wp, &procptr, sizeof(procptr));
1307
+ wp += sizeof(procptr);
1308
+ memcpy(wp, vbuf, vsiz);
1309
+ vbuf = rbuf + sizeof(procptr);
1310
+ } else {
1311
+ rbuf = (char *)stack;
1312
+ memcpy(rbuf, &procptr, sizeof(procptr));
1313
+ vbuf = rbuf + sizeof(procptr);
1314
+ vsiz = -1;
1315
+ }
1316
+ bool rv = tcfdbputimpl(fdb, id, vbuf, vsiz, FDBPDPROC);
1317
+ if(rbuf != (char *)stack) TCFREE(rbuf);
1318
+ FDBUNLOCKRECORD(fdb, id);
1319
+ FDBUNLOCKMETHOD(fdb);
1320
+ return rv;
1321
+ }
1322
+
1323
+
1324
+ /* Move the iterator to the record corresponding a key of a fixed-length database object. */
1325
+ bool tcfdbiterinit2(TCFDB *fdb, int64_t id){
1326
+ assert(fdb);
1327
+ if(!FDBLOCKMETHOD(fdb, true)) return false;
1328
+ if(fdb->fd < 0){
1329
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1330
+ FDBUNLOCKMETHOD(fdb);
1331
+ return false;
1332
+ }
1333
+ if(id == FDBIDMIN){
1334
+ id = fdb->min;
1335
+ } else if(id == FDBIDMAX){
1336
+ id = fdb->max;
1337
+ }
1338
+ if(id < 1 || id > fdb->limid){
1339
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1340
+ FDBUNLOCKMETHOD(fdb);
1341
+ return false;
1342
+ }
1343
+ bool rv = tcfdbiterjumpimpl(fdb, id);
1344
+ FDBUNLOCKMETHOD(fdb);
1345
+ return rv;
1346
+ }
1347
+
1348
+
1349
+ /* Move the iterator to the decimal record of a fixed-length database object. */
1350
+ bool tcfdbiterinit3(TCFDB *fdb, const void *kbuf, int ksiz){
1351
+ assert(fdb && kbuf && ksiz >= 0);
1352
+ return tcfdbiterinit2(fdb, tcfdbkeytoid(kbuf, ksiz));
1353
+ }
1354
+
1355
+
1356
+ /* Move the iterator to the decimal string record of a fixed-length database object. */
1357
+ bool tcfdbiterinit4(TCFDB *fdb, const char *kstr){
1358
+ assert(fdb && kstr);
1359
+ return tcfdbiterinit2(fdb, tcfdbkeytoid(kstr, strlen(kstr)));
1360
+ }
1361
+
1362
+
1363
+ /* Process each record atomically of a fixed-length database object. */
1364
+ bool tcfdbforeach(TCFDB *fdb, TCITER iter, void *op){
1365
+ assert(fdb && iter);
1366
+ if(!FDBLOCKMETHOD(fdb, false)) return false;
1367
+ if(fdb->fd < 0){
1368
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1369
+ FDBUNLOCKMETHOD(fdb);
1370
+ return false;
1371
+ }
1372
+ if(!FDBLOCKALLRECORDS(fdb, false)){
1373
+ FDBUNLOCKMETHOD(fdb);
1374
+ return false;
1375
+ }
1376
+ FDBTHREADYIELD(fdb);
1377
+ bool rv = tcfdbforeachimpl(fdb, iter, op);
1378
+ FDBUNLOCKALLRECORDS(fdb);
1379
+ FDBUNLOCKMETHOD(fdb);
1380
+ return rv;
1381
+ }
1382
+
1383
+
1384
+ /* Generate the ID number from arbitrary binary data. */
1385
+ int64_t tcfdbkeytoid(const char *kbuf, int ksiz){
1386
+ assert(kbuf && ksiz >= 0);
1387
+ if(ksiz == 3 && !memcmp(kbuf, "min", 3)){
1388
+ return FDBIDMIN;
1389
+ } else if(ksiz == 4 && !memcmp(kbuf, "prev", 4)){
1390
+ return FDBIDPREV;
1391
+ } else if(ksiz == 3 && !memcmp(kbuf, "max", 3)){
1392
+ return FDBIDMAX;
1393
+ } else if(ksiz == 4 && !memcmp(kbuf, "next", 4)){
1394
+ return FDBIDNEXT;
1395
+ }
1396
+ int64_t id = 0;
1397
+ const char *end = kbuf + ksiz;
1398
+ while(kbuf < end){
1399
+ int c = *(unsigned char *)(kbuf++);
1400
+ if(c >= '0' && c <= '9') id = id * 10 + c - '0';
1401
+ }
1402
+ return id;
1403
+ }
1404
+
1405
+
1406
+
1407
+ /*************************************************************************************************
1408
+ * private features
1409
+ *************************************************************************************************/
1410
+
1411
+
1412
+ /* Serialize meta data into a buffer.
1413
+ `fdb' specifies the fixed-length database object.
1414
+ `hbuf' specifies the buffer. */
1415
+ static void tcfdbdumpmeta(TCFDB *fdb, char *hbuf){
1416
+ memset(hbuf, 0, FDBHEADSIZ);
1417
+ sprintf(hbuf, "%s\n%s:%d\n", FDBMAGICDATA, _TC_FORMATVER, _TC_LIBVER);
1418
+ memcpy(hbuf + FDBTYPEOFF, &(fdb->type), sizeof(fdb->type));
1419
+ memcpy(hbuf + FDBFLAGSOFF, &(fdb->flags), sizeof(fdb->flags));
1420
+ uint64_t llnum;
1421
+ llnum = fdb->rnum;
1422
+ llnum = TCHTOILL(llnum);
1423
+ memcpy(hbuf + FDBRNUMOFF, &llnum, sizeof(llnum));
1424
+ llnum = fdb->fsiz;
1425
+ llnum = TCHTOILL(llnum);
1426
+ memcpy(hbuf + FDBFSIZOFF, &llnum, sizeof(llnum));
1427
+ llnum = fdb->width;
1428
+ llnum = TCHTOILL(llnum);
1429
+ memcpy(hbuf + FDBWIDTHOFF, &llnum, sizeof(llnum));
1430
+ llnum = fdb->limsiz;
1431
+ llnum = TCHTOILL(llnum);
1432
+ memcpy(hbuf + FDBLIMSIZOFF, &llnum, sizeof(llnum));
1433
+ llnum = fdb->min;
1434
+ llnum = TCHTOILL(llnum);
1435
+ memcpy(hbuf + FDBMINOFF, &llnum, sizeof(llnum));
1436
+ llnum = fdb->max;
1437
+ llnum = TCHTOILL(llnum);
1438
+ memcpy(hbuf + FDBMAXOFF, &llnum, sizeof(llnum));
1439
+ }
1440
+
1441
+
1442
+ /* Deserialize meta data from a buffer.
1443
+ `fdb' specifies the fixed-length database object.
1444
+ `hbuf' specifies the buffer. */
1445
+ static void tcfdbloadmeta(TCFDB *fdb, const char *hbuf){
1446
+ memcpy(&(fdb->type), hbuf + FDBTYPEOFF, sizeof(fdb->type));
1447
+ memcpy(&(fdb->flags), hbuf + FDBFLAGSOFF, sizeof(fdb->flags));
1448
+ uint64_t llnum;
1449
+ memcpy(&llnum, hbuf + FDBRNUMOFF, sizeof(llnum));
1450
+ fdb->rnum = TCITOHLL(llnum);
1451
+ memcpy(&llnum, hbuf + FDBFSIZOFF, sizeof(llnum));
1452
+ fdb->fsiz = TCITOHLL(llnum);
1453
+ memcpy(&llnum, hbuf + FDBWIDTHOFF, sizeof(llnum));
1454
+ fdb->width = TCITOHLL(llnum);
1455
+ memcpy(&llnum, hbuf + FDBLIMSIZOFF, sizeof(llnum));
1456
+ fdb->limsiz = TCITOHLL(llnum);
1457
+ memcpy(&llnum, hbuf + FDBMINOFF, sizeof(llnum));
1458
+ fdb->min = TCITOHLL(llnum);
1459
+ memcpy(&llnum, hbuf + FDBMAXOFF, sizeof(llnum));
1460
+ fdb->max = TCITOHLL(llnum);
1461
+ }
1462
+
1463
+
1464
+ /* Clear all members.
1465
+ `fdb' specifies the fixed-length database object. */
1466
+ static void tcfdbclear(TCFDB *fdb){
1467
+ assert(fdb);
1468
+ fdb->mmtx = NULL;
1469
+ fdb->amtx = NULL;
1470
+ fdb->rmtxs = NULL;
1471
+ fdb->tmtx = NULL;
1472
+ fdb->wmtx = NULL;
1473
+ fdb->eckey = NULL;
1474
+ fdb->rpath = NULL;
1475
+ fdb->type = TCDBTFIXED;
1476
+ fdb->flags = 0;
1477
+ fdb->width = FDBDEFWIDTH;
1478
+ fdb->limsiz = FDBDEFLIMSIZ;
1479
+ fdb->wsiz = 0;
1480
+ fdb->rsiz = 0;
1481
+ fdb->limid = 0;
1482
+ fdb->path = NULL;
1483
+ fdb->fd = -1;
1484
+ fdb->omode = 0;
1485
+ fdb->rnum = 0;
1486
+ fdb->fsiz = 0;
1487
+ fdb->min = 0;
1488
+ fdb->max = 0;
1489
+ fdb->iter = 0;
1490
+ fdb->map = NULL;
1491
+ fdb->array = NULL;
1492
+ fdb->ecode = TCESUCCESS;
1493
+ fdb->fatal = false;
1494
+ fdb->inode = 0;
1495
+ fdb->mtime = 0;
1496
+ fdb->tran = false;
1497
+ fdb->walfd = -1;
1498
+ fdb->walend = 0;
1499
+ fdb->dbgfd = -1;
1500
+ fdb->cnt_writerec = -1;
1501
+ fdb->cnt_readrec = -1;
1502
+ fdb->cnt_truncfile = -1;
1503
+ TCDODEBUG(fdb->cnt_writerec = 0);
1504
+ TCDODEBUG(fdb->cnt_readrec = 0);
1505
+ TCDODEBUG(fdb->cnt_truncfile = 0);
1506
+ }
1507
+
1508
+
1509
+ /* Set the open flag.
1510
+ `fdb' specifies the fixed-length database object.
1511
+ `flag' specifies the flag value.
1512
+ `sign' specifies the sign. */
1513
+ static void tcfdbsetflag(TCFDB *fdb, int flag, bool sign){
1514
+ assert(fdb);
1515
+ char *fp = (char *)fdb->map + FDBFLAGSOFF;
1516
+ if(sign){
1517
+ *fp |= (uint8_t)flag;
1518
+ } else {
1519
+ *fp &= ~(uint8_t)flag;
1520
+ }
1521
+ fdb->flags = *fp;
1522
+ }
1523
+
1524
+
1525
+ /* Initialize the write ahead logging file.
1526
+ `fdb' specifies the fixed-length database object.
1527
+ If successful, the return value is true, else, it is false. */
1528
+ static bool tcfdbwalinit(TCFDB *fdb){
1529
+ assert(fdb);
1530
+ if(lseek(fdb->walfd, 0, SEEK_SET) == -1){
1531
+ tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);
1532
+ return false;
1533
+ }
1534
+ if(ftruncate(fdb->walfd, 0) == -1){
1535
+ tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);
1536
+ return false;
1537
+ }
1538
+ uint64_t llnum = fdb->fsiz;
1539
+ llnum = TCHTOILL(llnum);
1540
+ if(!tcwrite(fdb->walfd, &llnum, sizeof(llnum))){
1541
+ tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__);
1542
+ return false;
1543
+ }
1544
+ fdb->walend = fdb->fsiz;
1545
+ if(!tcfdbwalwrite(fdb, 0, FDBHEADSIZ)) return false;
1546
+ return true;
1547
+ }
1548
+
1549
+
1550
+ /* Write an event into the write ahead logging file.
1551
+ `fdb' specifies the fixed-length database object.
1552
+ `off' specifies the offset of the region to be updated.
1553
+ `size' specifies the size of the region.
1554
+ If successful, the return value is true, else, it is false. */
1555
+ static bool tcfdbwalwrite(TCFDB *fdb, uint64_t off, int64_t size){
1556
+ assert(fdb && off >= 0 && size >= 0);
1557
+ if(off + size > fdb->walend) size = fdb->walend - off;
1558
+ if(size < 1) return true;
1559
+ char stack[FDBIOBUFSIZ];
1560
+ char *buf;
1561
+ if(size + sizeof(off) + sizeof(size) <= FDBIOBUFSIZ){
1562
+ buf = stack;
1563
+ } else {
1564
+ TCMALLOC(buf, size + sizeof(off) + sizeof(size));
1565
+ }
1566
+ char *wp = buf;
1567
+ uint64_t llnum = TCHTOILL(off);
1568
+ memcpy(wp, &llnum, sizeof(llnum));
1569
+ wp += sizeof(llnum);
1570
+ uint32_t lnum = TCHTOIL(size);
1571
+ memcpy(wp, &lnum, sizeof(lnum));
1572
+ wp += sizeof(lnum);
1573
+ memcpy(wp, fdb->map + off, size);
1574
+ wp += size;
1575
+ if(!FDBLOCKWAL(fdb)) return false;
1576
+ if(!tcwrite(fdb->walfd, buf, wp - buf)){
1577
+ tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__);
1578
+ if(buf != stack) TCFREE(buf);
1579
+ FDBUNLOCKWAL(fdb);
1580
+ return false;
1581
+ }
1582
+ if(buf != stack) TCFREE(buf);
1583
+ if((fdb->omode & FDBOTSYNC) && fsync(fdb->walfd) == -1){
1584
+ tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);
1585
+ FDBUNLOCKWAL(fdb);
1586
+ return false;
1587
+ }
1588
+ FDBUNLOCKWAL(fdb);
1589
+ return true;
1590
+ }
1591
+
1592
+
1593
+ /* Restore the database from the write ahead logging file.
1594
+ `fdb' specifies the fixed-length database object.
1595
+ `path' specifies the path of the database file.
1596
+ If successful, the return value is true, else, it is false. */
1597
+ static int tcfdbwalrestore(TCFDB *fdb, const char *path){
1598
+ assert(fdb && path);
1599
+ char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX);
1600
+ int walfd = open(tpath, O_RDONLY, FDBFILEMODE);
1601
+ TCFREE(tpath);
1602
+ if(walfd < 0) return false;
1603
+ bool err = false;
1604
+ uint64_t walsiz = 0;
1605
+ struct stat sbuf;
1606
+ if(fstat(walfd, &sbuf) == 0){
1607
+ walsiz = sbuf.st_size;
1608
+ } else {
1609
+ tcfdbsetecode(fdb, TCESTAT, __FILE__, __LINE__, __func__);
1610
+ err = true;
1611
+ }
1612
+ if(walsiz >= sizeof(walsiz) + FDBHEADSIZ){
1613
+ int dbfd = fdb->fd;
1614
+ int tfd = -1;
1615
+ if(!(fdb->omode & FDBOWRITER)){
1616
+ tfd = open(path, O_WRONLY, FDBFILEMODE);
1617
+ if(tfd >= 0){
1618
+ dbfd = tfd;
1619
+ } else {
1620
+ int ecode = TCEOPEN;
1621
+ switch(errno){
1622
+ case EACCES: ecode = TCENOPERM; break;
1623
+ case ENOENT: ecode = TCENOFILE; break;
1624
+ case ENOTDIR: ecode = TCENOFILE; break;
1625
+ }
1626
+ tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__);
1627
+ err = true;
1628
+ }
1629
+ }
1630
+ uint64_t fsiz = 0;
1631
+ if(tcread(walfd, &fsiz, sizeof(fsiz))){
1632
+ fsiz = TCITOHLL(fsiz);
1633
+ } else {
1634
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1635
+ err = true;
1636
+ }
1637
+ TCLIST *list = tclistnew();
1638
+ uint64_t waloff = sizeof(fsiz);
1639
+ char stack[FDBIOBUFSIZ];
1640
+ while(waloff < walsiz){
1641
+ uint64_t off;
1642
+ uint32_t size;
1643
+ if(!tcread(walfd, stack, sizeof(off) + sizeof(size))){
1644
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1645
+ err = true;
1646
+ break;
1647
+ }
1648
+ memcpy(&off, stack, sizeof(off));
1649
+ off = TCITOHLL(off);
1650
+ memcpy(&size, stack + sizeof(off), sizeof(size));
1651
+ size = TCITOHL(size);
1652
+ char *buf;
1653
+ if(sizeof(off) + size <= FDBIOBUFSIZ){
1654
+ buf = stack;
1655
+ } else {
1656
+ TCMALLOC(buf, sizeof(off) + size);
1657
+ }
1658
+ *(uint64_t *)buf = off;
1659
+ if(!tcread(walfd, buf + sizeof(off), size)){
1660
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1661
+ err = true;
1662
+ if(buf != stack) TCFREE(buf);
1663
+ break;
1664
+ }
1665
+ TCLISTPUSH(list, buf, sizeof(off) + size);
1666
+ if(buf != stack) TCFREE(buf);
1667
+ waloff += sizeof(off) + sizeof(size) + size;
1668
+ }
1669
+ for(int i = TCLISTNUM(list) - 1; i >= 0; i--){
1670
+ const char *rec;
1671
+ int size;
1672
+ TCLISTVAL(rec, list, i, size);
1673
+ uint64_t off = *(uint64_t *)rec;
1674
+ rec += sizeof(off);
1675
+ size -= sizeof(off);
1676
+ if(lseek(dbfd, off, SEEK_SET) == -1){
1677
+ tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);
1678
+ err = true;
1679
+ break;
1680
+ }
1681
+ if(!tcwrite(dbfd, rec, size)){
1682
+ tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__);
1683
+ err = true;
1684
+ break;
1685
+ }
1686
+ }
1687
+ tclistdel(list);
1688
+ if(ftruncate(dbfd, fsiz) == -1){
1689
+ tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);
1690
+ err = true;
1691
+ }
1692
+ if((fdb->omode & FDBOTSYNC) && fsync(dbfd) == -1){
1693
+ tcfdbsetecode(fdb, TCESYNC, __FILE__, __LINE__, __func__);
1694
+ err = true;
1695
+ }
1696
+ if(tfd >= 0 && close(tfd) == -1){
1697
+ tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__);
1698
+ err = true;
1699
+ }
1700
+ } else {
1701
+ err = true;
1702
+ }
1703
+ if(close(walfd) == -1){
1704
+ tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__);
1705
+ err = true;
1706
+ }
1707
+ return !err;
1708
+ }
1709
+
1710
+
1711
+ /* Remove the write ahead logging file.
1712
+ `fdb' specifies the fixed-length database object.
1713
+ `path' specifies the path of the database file.
1714
+ If successful, the return value is true, else, it is false. */
1715
+ static bool tcfdbwalremove(TCFDB *fdb, const char *path){
1716
+ assert(fdb && path);
1717
+ char *tpath = tcsprintf("%s%c%s", path, MYEXTCHR, FDBWALSUFFIX);
1718
+ bool err = false;
1719
+ if(unlink(tpath) == -1 && errno != ENOENT){
1720
+ tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__);
1721
+ err = true;
1722
+ }
1723
+ TCFREE(tpath);
1724
+ return !err;
1725
+ }
1726
+
1727
+
1728
+ /* Open a database file and connect a fixed-length database object.
1729
+ `fdb' specifies the fixed-length database object.
1730
+ `path' specifies the path of the database file.
1731
+ `omode' specifies the connection mode.
1732
+ If successful, the return value is true, else, it is false. */
1733
+ static bool tcfdbopenimpl(TCFDB *fdb, const char *path, int omode){
1734
+ assert(fdb && path);
1735
+ int mode = O_RDONLY;
1736
+ if(omode & FDBOWRITER){
1737
+ mode = O_RDWR;
1738
+ if(omode & FDBOCREAT) mode |= O_CREAT;
1739
+ }
1740
+ int fd = open(path, mode, FDBFILEMODE);
1741
+ if(fd < 0){
1742
+ int ecode = TCEOPEN;
1743
+ switch(errno){
1744
+ case EACCES: ecode = TCENOPERM; break;
1745
+ case ENOENT: ecode = TCENOFILE; break;
1746
+ case ENOTDIR: ecode = TCENOFILE; break;
1747
+ }
1748
+ tcfdbsetecode(fdb, ecode, __FILE__, __LINE__, __func__);
1749
+ return false;
1750
+ }
1751
+ if(!(omode & FDBONOLCK)){
1752
+ if(!tclock(fd, omode & FDBOWRITER, omode & FDBOLCKNB)){
1753
+ tcfdbsetecode(fdb, TCELOCK, __FILE__, __LINE__, __func__);
1754
+ close(fd);
1755
+ return false;
1756
+ }
1757
+ }
1758
+ if((omode & FDBOWRITER) && (omode & FDBOTRUNC)){
1759
+ if(ftruncate(fd, 0) == -1){
1760
+ tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);
1761
+ close(fd);
1762
+ return false;
1763
+ }
1764
+ if(!tcfdbwalremove(fdb, path)){
1765
+ close(fd);
1766
+ return false;
1767
+ }
1768
+ }
1769
+ struct stat sbuf;
1770
+ if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
1771
+ tcfdbsetecode(fdb, TCESTAT, __FILE__, __LINE__, __func__);
1772
+ close(fd);
1773
+ return false;
1774
+ }
1775
+ char hbuf[FDBHEADSIZ];
1776
+ if((omode & FDBOWRITER) && sbuf.st_size < 1){
1777
+ fdb->flags = 0;
1778
+ fdb->rnum = 0;
1779
+ fdb->fsiz = FDBHEADSIZ;
1780
+ fdb->min = 0;
1781
+ fdb->max = 0;
1782
+ tcfdbdumpmeta(fdb, hbuf);
1783
+ if(!tcwrite(fd, hbuf, FDBHEADSIZ)){
1784
+ tcfdbsetecode(fdb, TCEWRITE, __FILE__, __LINE__, __func__);
1785
+ close(fd);
1786
+ return false;
1787
+ }
1788
+ sbuf.st_size = fdb->fsiz;
1789
+ }
1790
+ if(lseek(fd, 0, SEEK_SET) == -1){
1791
+ tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);
1792
+ close(fd);
1793
+ return false;
1794
+ }
1795
+ if(!tcread(fd, hbuf, FDBHEADSIZ)){
1796
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1797
+ close(fd);
1798
+ return false;
1799
+ }
1800
+ int type = fdb->type;
1801
+ tcfdbloadmeta(fdb, hbuf);
1802
+ if((fdb->flags & FDBFOPEN) && tcfdbwalrestore(fdb, path)){
1803
+ if(lseek(fd, 0, SEEK_SET) == -1){
1804
+ tcfdbsetecode(fdb, TCESEEK, __FILE__, __LINE__, __func__);
1805
+ close(fd);
1806
+ return false;
1807
+ }
1808
+ if(!tcread(fd, hbuf, FDBHEADSIZ)){
1809
+ tcfdbsetecode(fdb, TCEREAD, __FILE__, __LINE__, __func__);
1810
+ close(fd);
1811
+ return false;
1812
+ }
1813
+ tcfdbloadmeta(fdb, hbuf);
1814
+ if(!tcfdbwalremove(fdb, path)){
1815
+ close(fd);
1816
+ return false;
1817
+ }
1818
+ }
1819
+ if(!(omode & FDBONOLCK)){
1820
+ if(memcmp(hbuf, FDBMAGICDATA, strlen(FDBMAGICDATA)) || fdb->type != type ||
1821
+ fdb->width < 1 || sbuf.st_size < fdb->fsiz || fdb->limsiz < FDBHEADSIZ ||
1822
+ fdb->fsiz > fdb->limsiz){
1823
+ tcfdbsetecode(fdb, TCEMETA, __FILE__, __LINE__, __func__);
1824
+ close(fd);
1825
+ return false;
1826
+ }
1827
+ if(sbuf.st_size > fdb->fsiz) fdb->fsiz = sbuf.st_size;
1828
+ }
1829
+ void *map = mmap(0, fdb->limsiz, PROT_READ | ((omode & FDBOWRITER) ? PROT_WRITE : 0),
1830
+ MAP_SHARED, fd, 0);
1831
+ if(map == MAP_FAILED){
1832
+ tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__);
1833
+ close(fd);
1834
+ return false;
1835
+ }
1836
+ if(fdb->width <= UINT8_MAX){
1837
+ fdb->wsiz = sizeof(uint8_t);
1838
+ } else if(fdb->width <= UINT16_MAX){
1839
+ fdb->wsiz = sizeof(uint16_t);
1840
+ } else {
1841
+ fdb->wsiz = sizeof(uint32_t);
1842
+ }
1843
+ fdb->rsiz = fdb->width + fdb->wsiz;
1844
+ fdb->limid = (fdb->limsiz - FDBHEADSIZ) / fdb->rsiz;
1845
+ fdb->path = tcstrdup(path);
1846
+ fdb->fd = fd;
1847
+ fdb->omode = omode;
1848
+ fdb->iter = 0;
1849
+ fdb->map = map;
1850
+ fdb->array = (unsigned char *)map + FDBHEADSIZ;
1851
+ fdb->ecode = TCESUCCESS;
1852
+ fdb->fatal = false;
1853
+ fdb->inode = (uint64_t)sbuf.st_ino;
1854
+ fdb->mtime = sbuf.st_mtime;
1855
+ fdb->tran = false;
1856
+ fdb->walfd = -1;
1857
+ fdb->walend = 0;
1858
+ if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true);
1859
+ return true;
1860
+ }
1861
+
1862
+
1863
+ /* Close a fixed-length database object.
1864
+ `fdb' specifies the fixed-length database object.
1865
+ If successful, the return value is true, else, it is false. */
1866
+ static bool tcfdbcloseimpl(TCFDB *fdb){
1867
+ assert(fdb);
1868
+ bool err = false;
1869
+ if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, false);
1870
+ if((fdb->omode & FDBOWRITER) && !tcfdbmemsync(fdb, false)) err = true;
1871
+ if(munmap(fdb->map, fdb->limsiz) == -1){
1872
+ tcfdbsetecode(fdb, TCEMMAP, __FILE__, __LINE__, __func__);
1873
+ err = true;
1874
+ }
1875
+ if(fdb->tran){
1876
+ if(!tcfdbwalrestore(fdb, fdb->path)) err = true;
1877
+ fdb->tran = false;
1878
+ }
1879
+ if(fdb->walfd >= 0){
1880
+ if(close(fdb->walfd) == -1){
1881
+ tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__);
1882
+ err = true;
1883
+ }
1884
+ if(!fdb->fatal && !tcfdbwalremove(fdb, fdb->path)) err = true;
1885
+ }
1886
+ if(close(fdb->fd) == -1){
1887
+ tcfdbsetecode(fdb, TCECLOSE, __FILE__, __LINE__, __func__);
1888
+ err = true;
1889
+ }
1890
+ TCFREE(fdb->path);
1891
+ fdb->path = NULL;
1892
+ fdb->fd = -1;
1893
+ return !err;
1894
+ }
1895
+
1896
+
1897
+ /* Get the previous record of a record.
1898
+ `fdb' specifies the fixed-length database object.
1899
+ `id' specifies the ID number.
1900
+ The return value is the ID number of the previous record or 0 if no record corresponds. */
1901
+ static int64_t tcfdbprevid(TCFDB *fdb, int64_t id){
1902
+ assert(fdb && id >= 0);
1903
+ id--;
1904
+ while(id >= fdb->min){
1905
+ TCDODEBUG(fdb->cnt_readrec++);
1906
+ unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz);
1907
+ unsigned char *rp = rec;
1908
+ uint32_t osiz;
1909
+ uint16_t snum;
1910
+ uint32_t lnum;
1911
+ switch(fdb->wsiz){
1912
+ case 1:
1913
+ osiz = *(rp++);
1914
+ break;
1915
+ case 2:
1916
+ memcpy(&snum, rp, sizeof(snum));
1917
+ osiz = TCITOHS(snum);
1918
+ rp += sizeof(snum);
1919
+ break;
1920
+ default:
1921
+ memcpy(&lnum, rp, sizeof(lnum));
1922
+ osiz = TCITOHL(lnum);
1923
+ rp += sizeof(lnum);
1924
+ break;
1925
+ }
1926
+ if(osiz > 0 || *rp != 0) return id;
1927
+ id--;
1928
+ }
1929
+ return 0;
1930
+ }
1931
+
1932
+
1933
+ /* Get the next record of a record.
1934
+ `fdb' specifies the fixed-length database object.
1935
+ `id' specifies the ID number.
1936
+ The return value is the ID number of the next record or 0 if no record corresponds. */
1937
+ static int64_t tcfdbnextid(TCFDB *fdb, int64_t id){
1938
+ assert(fdb && id >= 0);
1939
+ id++;
1940
+ while(id <= fdb->max){
1941
+ TCDODEBUG(fdb->cnt_readrec++);
1942
+ unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz);
1943
+ unsigned char *rp = rec;
1944
+ uint32_t osiz;
1945
+ uint16_t snum;
1946
+ uint32_t lnum;
1947
+ switch(fdb->wsiz){
1948
+ case 1:
1949
+ osiz = *(rp++);
1950
+ break;
1951
+ case 2:
1952
+ memcpy(&snum, rp, sizeof(snum));
1953
+ osiz = TCITOHS(snum);
1954
+ rp += sizeof(snum);
1955
+ break;
1956
+ default:
1957
+ memcpy(&lnum, rp, sizeof(lnum));
1958
+ osiz = TCITOHL(lnum);
1959
+ rp += sizeof(lnum);
1960
+ break;
1961
+ }
1962
+ if(osiz > 0 || *rp != 0) return id;
1963
+ id++;
1964
+ }
1965
+ return 0;
1966
+ }
1967
+
1968
+
1969
+ /* Store a record.
1970
+ `fdb' specifies the fixed-length database object.
1971
+ `id' specifies the ID number.
1972
+ `vbuf' specifies the pointer to the region of the value.
1973
+ `vsiz' specifies the size of the region of the value.
1974
+ `dmode' specifies behavior when the key overlaps.
1975
+ If successful, the return value is true, else, it is false. */
1976
+ static bool tcfdbputimpl(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, int dmode){
1977
+ assert(fdb && id > 0);
1978
+ if(vsiz > (int64_t)fdb->width) vsiz = fdb->width;
1979
+ TCDODEBUG(fdb->cnt_readrec++);
1980
+ unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz);
1981
+ uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz;
1982
+ if(nsiz > fdb->fsiz){
1983
+ if(nsiz > fdb->limsiz){
1984
+ tcfdbsetecode(fdb, TCEINVALID, __FILE__, __LINE__, __func__);
1985
+ return false;
1986
+ }
1987
+ if(!FDBLOCKATTR(fdb)) return false;
1988
+ if(nsiz > fdb->fsiz){
1989
+ if(vsiz < 0){
1990
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
1991
+ FDBUNLOCKATTR(fdb);
1992
+ return false;
1993
+ }
1994
+ if(nsiz + fdb->rsiz * FDBTRUNCALW < fdb->limsiz) nsiz += fdb->rsiz * FDBTRUNCALW;
1995
+ if(ftruncate(fdb->fd, nsiz) == -1){
1996
+ tcfdbsetecode(fdb, TCETRUNC, __FILE__, __LINE__, __func__);
1997
+ FDBUNLOCKATTR(fdb);
1998
+ return false;
1999
+ }
2000
+ TCDODEBUG(fdb->cnt_truncfile++);
2001
+ fdb->fsiz = nsiz;
2002
+ unsigned char *wp = rec;
2003
+ uint16_t snum;
2004
+ uint32_t lnum;
2005
+ switch(fdb->wsiz){
2006
+ case 1:
2007
+ *(wp++) = vsiz;
2008
+ break;
2009
+ case 2:
2010
+ snum = TCHTOIS(vsiz);
2011
+ memcpy(wp, &snum, sizeof(snum));
2012
+ wp += sizeof(snum);
2013
+ break;
2014
+ default:
2015
+ lnum = TCHTOIL(vsiz);
2016
+ memcpy(wp, &lnum, sizeof(lnum));
2017
+ wp += sizeof(lnum);
2018
+ break;
2019
+ }
2020
+ if(vsiz > 0){
2021
+ memcpy(wp, vbuf, vsiz);
2022
+ } else {
2023
+ *wp = 1;
2024
+ }
2025
+ TCDODEBUG(fdb->cnt_writerec++);
2026
+ fdb->rnum++;
2027
+ if(fdb->min < 1 || id < fdb->min) fdb->min = id;
2028
+ if(fdb->max < 1 || id > fdb->max) fdb->max = id;
2029
+ FDBUNLOCKATTR(fdb);
2030
+ return true;
2031
+ }
2032
+ FDBUNLOCKATTR(fdb);
2033
+ }
2034
+ unsigned char *rp = rec;
2035
+ uint32_t osiz;
2036
+ uint16_t snum;
2037
+ uint32_t lnum;
2038
+ switch(fdb->wsiz){
2039
+ case 1:
2040
+ osiz = *(rp++);
2041
+ break;
2042
+ case 2:
2043
+ memcpy(&snum, rp, sizeof(snum));
2044
+ osiz = TCITOHS(snum);
2045
+ rp += sizeof(snum);
2046
+ break;
2047
+ default:
2048
+ memcpy(&lnum, rp, sizeof(lnum));
2049
+ osiz = TCITOHL(lnum);
2050
+ rp += sizeof(lnum);
2051
+ break;
2052
+ }
2053
+ bool miss = osiz == 0 && *rp == 0;
2054
+ if(dmode != FDBPDOVER && !miss){
2055
+ if(dmode == FDBPDKEEP){
2056
+ tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__);
2057
+ return false;
2058
+ }
2059
+ if(dmode == FDBPDCAT){
2060
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2061
+ vsiz = tclmin(vsiz, fdb->width - osiz);
2062
+ unsigned char *wp = rec;
2063
+ int usiz = osiz + vsiz;
2064
+ switch(fdb->wsiz){
2065
+ case 1:
2066
+ *(wp++) = usiz;
2067
+ break;
2068
+ case 2:
2069
+ snum = TCHTOIS(usiz);
2070
+ memcpy(wp, &snum, sizeof(snum));
2071
+ wp += sizeof(snum);
2072
+ break;
2073
+ default:
2074
+ lnum = TCHTOIL(usiz);
2075
+ memcpy(wp, &lnum, sizeof(lnum));
2076
+ wp += sizeof(lnum);
2077
+ break;
2078
+ }
2079
+ if(usiz > 0){
2080
+ memcpy(wp + osiz, vbuf, vsiz);
2081
+ } else {
2082
+ *wp = 1;
2083
+ }
2084
+ TCDODEBUG(fdb->cnt_writerec++);
2085
+ return true;
2086
+ }
2087
+ if(dmode == FDBPDADDINT){
2088
+ if(osiz != sizeof(int)){
2089
+ tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__);
2090
+ return false;
2091
+ }
2092
+ int lnum;
2093
+ memcpy(&lnum, rp, sizeof(lnum));
2094
+ if(*(int *)vbuf == 0){
2095
+ *(int *)vbuf = lnum;
2096
+ return true;
2097
+ }
2098
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2099
+ lnum += *(int *)vbuf;
2100
+ *(int *)vbuf = lnum;
2101
+ memcpy(rp, &lnum, sizeof(lnum));
2102
+ TCDODEBUG(fdb->cnt_writerec++);
2103
+ return true;
2104
+ }
2105
+ if(dmode == FDBPDADDDBL){
2106
+ if(osiz != sizeof(double)){
2107
+ tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__);
2108
+ return false;
2109
+ }
2110
+ double dnum;
2111
+ memcpy(&dnum, rp, sizeof(dnum));
2112
+ if(*(double *)vbuf == 0.0){
2113
+ *(double *)vbuf = dnum;
2114
+ return true;
2115
+ }
2116
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2117
+ dnum += *(double *)vbuf;
2118
+ *(double *)vbuf = dnum;
2119
+ memcpy(rp, &dnum, sizeof(dnum));
2120
+ TCDODEBUG(fdb->cnt_writerec++);
2121
+ return true;
2122
+ }
2123
+ if(dmode == FDBPDPROC){
2124
+ FDBPDPROCOP *procptr = *(FDBPDPROCOP **)((char *)vbuf - sizeof(procptr));
2125
+ int nvsiz;
2126
+ char *nvbuf = procptr->proc(rp, osiz, &nvsiz, procptr->op);
2127
+ if(nvbuf == (void *)-1){
2128
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2129
+ memset(rec, 0, fdb->wsiz + 1);
2130
+ TCDODEBUG(fdb->cnt_writerec++);
2131
+ if(!FDBLOCKATTR(fdb)) return false;
2132
+ fdb->rnum--;
2133
+ if(fdb->rnum < 1){
2134
+ fdb->min = 0;
2135
+ fdb->max = 0;
2136
+ } else if(fdb->rnum < 2){
2137
+ if(fdb->min == id){
2138
+ fdb->min = fdb->max;
2139
+ } else if(fdb->max == id){
2140
+ fdb->max = fdb->min;
2141
+ }
2142
+ } else {
2143
+ if(id == fdb->min) fdb->min = tcfdbnextid(fdb, id);
2144
+ if(id == fdb->max) fdb->max = tcfdbprevid(fdb, id);
2145
+ }
2146
+ FDBUNLOCKATTR(fdb);
2147
+ return true;
2148
+ }
2149
+ if(!nvbuf){
2150
+ tcfdbsetecode(fdb, TCEKEEP, __FILE__, __LINE__, __func__);
2151
+ return false;
2152
+ }
2153
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2154
+ if(nvsiz > fdb->width) nvsiz = fdb->width;
2155
+ unsigned char *wp = rec;
2156
+ switch(fdb->wsiz){
2157
+ case 1:
2158
+ *(wp++) = nvsiz;
2159
+ break;
2160
+ case 2:
2161
+ snum = TCHTOIS(nvsiz);
2162
+ memcpy(wp, &snum, sizeof(snum));
2163
+ wp += sizeof(snum);
2164
+ break;
2165
+ default:
2166
+ lnum = TCHTOIL(nvsiz);
2167
+ memcpy(wp, &lnum, sizeof(lnum));
2168
+ wp += sizeof(lnum);
2169
+ break;
2170
+ }
2171
+ if(nvsiz > 0){
2172
+ memcpy(wp, nvbuf, nvsiz);
2173
+ } else {
2174
+ *wp = 1;
2175
+ }
2176
+ TCFREE(nvbuf);
2177
+ TCDODEBUG(fdb->cnt_writerec++);
2178
+ return true;
2179
+ }
2180
+ }
2181
+ if(vsiz < 0){
2182
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2183
+ return false;
2184
+ }
2185
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2186
+ unsigned char *wp = rec;
2187
+ switch(fdb->wsiz){
2188
+ case 1:
2189
+ *(wp++) = vsiz;
2190
+ break;
2191
+ case 2:
2192
+ snum = TCHTOIS(vsiz);
2193
+ memcpy(wp, &snum, sizeof(snum));
2194
+ wp += sizeof(snum);
2195
+ break;
2196
+ default:
2197
+ lnum = TCHTOIL(vsiz);
2198
+ memcpy(wp, &lnum, sizeof(lnum));
2199
+ wp += sizeof(lnum);
2200
+ break;
2201
+ }
2202
+ if(vsiz > 0){
2203
+ memcpy(wp, vbuf, vsiz);
2204
+ } else {
2205
+ *wp = 1;
2206
+ }
2207
+ TCDODEBUG(fdb->cnt_writerec++);
2208
+ if(miss){
2209
+ if(!FDBLOCKATTR(fdb)) return false;
2210
+ fdb->rnum++;
2211
+ if(fdb->min < 1 || id < fdb->min) fdb->min = id;
2212
+ if(fdb->max < 1 || id > fdb->max) fdb->max = id;
2213
+ FDBUNLOCKATTR(fdb);
2214
+ }
2215
+ return true;
2216
+ }
2217
+
2218
+
2219
+ /* Remove a record of a fixed-length database object.
2220
+ `fdb' specifies the fixed-length database object.
2221
+ `id' specifies the ID number.
2222
+ If successful, the return value is true, else, it is false. */
2223
+ static bool tcfdboutimpl(TCFDB *fdb, int64_t id){
2224
+ assert(fdb && id >= 0);
2225
+ TCDODEBUG(fdb->cnt_readrec++);
2226
+ unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz);
2227
+ uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz;
2228
+ if(nsiz > fdb->fsiz){
2229
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2230
+ return false;
2231
+ }
2232
+ unsigned char *rp = rec;
2233
+ uint32_t osiz;
2234
+ uint16_t snum;
2235
+ uint32_t lnum;
2236
+ switch(fdb->wsiz){
2237
+ case 1:
2238
+ osiz = *(rp++);
2239
+ break;
2240
+ case 2:
2241
+ memcpy(&snum, rp, sizeof(snum));
2242
+ osiz = TCITOHS(snum);
2243
+ rp += sizeof(snum);
2244
+ break;
2245
+ default:
2246
+ memcpy(&lnum, rp, sizeof(lnum));
2247
+ osiz = TCITOHL(lnum);
2248
+ rp += sizeof(lnum);
2249
+ break;
2250
+ }
2251
+ if(osiz == 0 && *rp == 0){
2252
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2253
+ return false;
2254
+ }
2255
+ if(fdb->tran && !tcfdbwalwrite(fdb, (char *)rec - fdb->map, fdb->width)) return false;
2256
+ memset(rec, 0, fdb->wsiz + 1);
2257
+ TCDODEBUG(fdb->cnt_writerec++);
2258
+ if(!FDBLOCKATTR(fdb)) return false;
2259
+ fdb->rnum--;
2260
+ if(fdb->rnum < 1){
2261
+ fdb->min = 0;
2262
+ fdb->max = 0;
2263
+ } else if(fdb->rnum < 2){
2264
+ if(fdb->min == id){
2265
+ fdb->min = fdb->max;
2266
+ } else if(fdb->max == id){
2267
+ fdb->max = fdb->min;
2268
+ }
2269
+ } else {
2270
+ if(id == fdb->min) fdb->min = tcfdbnextid(fdb, id);
2271
+ if(id == fdb->max) fdb->max = tcfdbprevid(fdb, id);
2272
+ }
2273
+ FDBUNLOCKATTR(fdb);
2274
+ return true;
2275
+ }
2276
+
2277
+
2278
+ /* Retrieve a record.
2279
+ `fdb' specifies the fixed-length database object.
2280
+ `id' specifies the ID number.
2281
+ `sp' specifies the pointer to the variable into which the size of the region of the return
2282
+ value is assigned.
2283
+ If successful, the return value is the pointer to the region of the value of the corresponding
2284
+ record. */
2285
+ static const void *tcfdbgetimpl(TCFDB *fdb, int64_t id, int *sp){
2286
+ assert(fdb && id >= 0 && sp);
2287
+ TCDODEBUG(fdb->cnt_readrec++);
2288
+ unsigned char *rec = fdb->array + (id - 1) * (fdb->rsiz);
2289
+ uint64_t nsiz = FDBHEADSIZ + id * fdb->rsiz;
2290
+ if(nsiz > fdb->fsiz){
2291
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2292
+ return false;
2293
+ }
2294
+ unsigned char *rp = rec;
2295
+ uint32_t osiz;
2296
+ uint16_t snum;
2297
+ uint32_t lnum;
2298
+ switch(fdb->wsiz){
2299
+ case 1:
2300
+ osiz = *(rp++);
2301
+ break;
2302
+ case 2:
2303
+ memcpy(&snum, rp, sizeof(snum));
2304
+ osiz = TCITOHS(snum);
2305
+ rp += sizeof(snum);
2306
+ break;
2307
+ default:
2308
+ memcpy(&lnum, rp, sizeof(lnum));
2309
+ osiz = TCITOHL(lnum);
2310
+ rp += sizeof(lnum);
2311
+ break;
2312
+ }
2313
+ if(osiz == 0 && *rp == 0){
2314
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2315
+ return false;
2316
+ }
2317
+ *sp = osiz;
2318
+ return rp;
2319
+ }
2320
+
2321
+
2322
+ /* Initialize the iterator of a fixed-length database object.
2323
+ `fdb' specifies the fixed-length database object.
2324
+ If successful, the return value is true, else, it is false. */
2325
+ static bool tcfdbiterinitimpl(TCFDB *fdb){
2326
+ assert(fdb);
2327
+ fdb->iter = fdb->min;
2328
+ return true;
2329
+ }
2330
+
2331
+
2332
+ /* Get the next key of the iterator of a fixed-length database object.
2333
+ `fdb' specifies the fixed-length database object.
2334
+ If successful, the return value is the next ID number of the iterator, else, it is 0. */
2335
+ static uint64_t tcfdbiternextimpl(TCFDB *fdb){
2336
+ assert(fdb);
2337
+ if(fdb->iter < 1){
2338
+ tcfdbsetecode(fdb, TCENOREC, __FILE__, __LINE__, __func__);
2339
+ return 0;
2340
+ }
2341
+ uint64_t cur = fdb->iter;
2342
+ fdb->iter = tcfdbnextid(fdb, fdb->iter);
2343
+ return cur;
2344
+ }
2345
+
2346
+
2347
+ /* Get range matching ID numbers in a fixed-length database object.
2348
+ `fdb' specifies the fixed-length database object.
2349
+ `lower' specifies the lower limit of the range.
2350
+ `upper' specifies the upper limit of the range.
2351
+ `max' specifies the maximum number of keys to be fetched.
2352
+ `np' specifies the pointer to the variable into which the number of elements of the return
2353
+ value is assigned.
2354
+ If successful, the return value is the pointer to an array of ID numbers of the corresponding
2355
+ records. */
2356
+ static uint64_t *tcfdbrangeimpl(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np){
2357
+ assert(fdb && lower > 0 && upper > 0 && np);
2358
+ if(lower < fdb->min) lower = fdb->min;
2359
+ if(upper > fdb->max) upper = fdb->max;
2360
+ if(max < 0) max = INT_MAX;
2361
+ int anum = FDBIDARYUNIT;
2362
+ uint64_t *ids;
2363
+ TCMALLOC(ids, anum * sizeof(*ids));
2364
+ int num = 0;
2365
+ for(int64_t i = lower; i <= upper && num < max; i++){
2366
+ int vsiz;
2367
+ const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz);
2368
+ if(vbuf){
2369
+ if(num >= anum){
2370
+ anum *= 2;
2371
+ TCREALLOC(ids, ids, anum * sizeof(*ids));
2372
+ }
2373
+ ids[num++] = i;
2374
+ }
2375
+ }
2376
+ *np = num;
2377
+ return ids;
2378
+ }
2379
+
2380
+
2381
+ /* Optimize the file of a fixed-length database object.
2382
+ `fdb' specifies the fixed-length database object.
2383
+ `width' specifies the width of the value of each record.
2384
+ `limsiz' specifies the limit size of the database file.
2385
+ If successful, the return value is true, else, it is false. */
2386
+ static bool tcfdboptimizeimpl(TCFDB *fdb, int32_t width, int64_t limsiz){
2387
+ assert(fdb);
2388
+ char *tpath = tcsprintf("%s%ctmp%c%llu", fdb->path, MYEXTCHR, MYEXTCHR, fdb->inode);
2389
+ TCFDB *tfdb = tcfdbnew();
2390
+ tfdb->dbgfd = fdb->dbgfd;
2391
+ if(width < 1) width = fdb->width;
2392
+ if(limsiz < 1) limsiz = fdb->limsiz;
2393
+ tcfdbtune(tfdb, width, limsiz);
2394
+ if(!tcfdbopen(tfdb, tpath, FDBOWRITER | FDBOCREAT | FDBOTRUNC)){
2395
+ tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__);
2396
+ tcfdbdel(tfdb);
2397
+ TCFREE(tpath);
2398
+ return false;
2399
+ }
2400
+ bool err = false;
2401
+ int64_t max = fdb->max;
2402
+ for(int i = fdb->min; !err && i <= max; i++){
2403
+ int vsiz;
2404
+ const void *vbuf = tcfdbgetimpl(fdb, i, &vsiz);
2405
+ if(vbuf && !tcfdbput(tfdb, i, vbuf, vsiz)){
2406
+ tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__);
2407
+ err = true;
2408
+ }
2409
+ }
2410
+ if(!tcfdbclose(tfdb)){
2411
+ tcfdbsetecode(fdb, tfdb->ecode, __FILE__, __LINE__, __func__);
2412
+ err = true;
2413
+ }
2414
+ tcfdbdel(tfdb);
2415
+ if(unlink(fdb->path) == -1){
2416
+ tcfdbsetecode(fdb, TCEUNLINK, __FILE__, __LINE__, __func__);
2417
+ err = true;
2418
+ }
2419
+ if(rename(tpath, fdb->path) == -1){
2420
+ tcfdbsetecode(fdb, TCERENAME, __FILE__, __LINE__, __func__);
2421
+ err = true;
2422
+ }
2423
+ TCFREE(tpath);
2424
+ if(err) return false;
2425
+ tpath = tcstrdup(fdb->path);
2426
+ int omode = (fdb->omode & ~FDBOCREAT) & ~FDBOTRUNC;
2427
+ if(!tcfdbcloseimpl(fdb)){
2428
+ TCFREE(tpath);
2429
+ return false;
2430
+ }
2431
+ bool rv = tcfdbopenimpl(fdb, tpath, omode);
2432
+ TCFREE(tpath);
2433
+ return rv;
2434
+ }
2435
+
2436
+
2437
+ /* Remove all records of a fixed-length database object.
2438
+ `fdb' specifies the fixed-length database object.
2439
+ If successful, the return value is true, else, it is false. */
2440
+ static bool tcfdbvanishimpl(TCFDB *fdb){
2441
+ assert(fdb);
2442
+ char *path = tcstrdup(fdb->path);
2443
+ int omode = fdb->omode;
2444
+ bool err = false;
2445
+ if(!tcfdbcloseimpl(fdb)) err = true;
2446
+ if(!tcfdbopenimpl(fdb, path, FDBOTRUNC | omode)){
2447
+ tcpathunlock(fdb->rpath);
2448
+ TCFREE(fdb->rpath);
2449
+ err = true;
2450
+ }
2451
+ TCFREE(path);
2452
+ return !err;
2453
+ }
2454
+
2455
+
2456
+ /* Copy the database file of a fixed-length database object.
2457
+ `fdb' specifies the fixed-length database object.
2458
+ `path' specifies the path of the destination file.
2459
+ If successful, the return value is true, else, it is false. */
2460
+ static bool tcfdbcopyimpl(TCFDB *fdb, const char *path){
2461
+ assert(fdb && path);
2462
+ bool err = false;
2463
+ if(fdb->omode & FDBOWRITER){
2464
+ if(!tcfdbmemsync(fdb, false)) err = true;
2465
+ tcfdbsetflag(fdb, FDBFOPEN, false);
2466
+ }
2467
+ if(*path == '@'){
2468
+ char tsbuf[TCNUMBUFSIZ];
2469
+ sprintf(tsbuf, "%llu", (unsigned long long)(tctime() * 1000000));
2470
+ const char *args[3];
2471
+ args[0] = path + 1;
2472
+ args[1] = fdb->path;
2473
+ args[2] = tsbuf;
2474
+ if(tcsystem(args, sizeof(args) / sizeof(*args)) != 0) err = true;
2475
+ } else {
2476
+ if(!tccopyfile(fdb->path, path)){
2477
+ tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__);
2478
+ err = true;
2479
+ }
2480
+ }
2481
+ if(fdb->omode & FDBOWRITER) tcfdbsetflag(fdb, FDBFOPEN, true);
2482
+ return !err;
2483
+ }
2484
+
2485
+
2486
+ /* Move the iterator to the record corresponding a key of a fixed-length database object.
2487
+ `fdb' specifies the fixed-length database object.
2488
+ `id' specifies the ID number.
2489
+ If successful, the return value is true, else, it is false. */
2490
+ static bool tcfdbiterjumpimpl(TCFDB *fdb, int64_t id){
2491
+ assert(fdb && id >= 0);
2492
+ if(id <= fdb->min){
2493
+ fdb->iter = fdb->min;
2494
+ } else {
2495
+ int vsiz;
2496
+ if(tcfdbgetimpl(fdb, id, &vsiz)){
2497
+ fdb->iter = id;
2498
+ } else {
2499
+ uint64_t iter = tcfdbnextid(fdb, id);
2500
+ if(iter > 0){
2501
+ fdb->iter = iter;
2502
+ } else {
2503
+ return false;
2504
+ }
2505
+ }
2506
+ }
2507
+ return true;
2508
+ }
2509
+
2510
+
2511
+ /* Process each record atomically of a fixed-length database object.
2512
+ `fdb' specifies the fixed-length database object.
2513
+ `iter' specifies the pointer to the iterator function called for each record.
2514
+ `op' specifies an arbitrary pointer to be given as a parameter of the iterator function.
2515
+ If successful, the return value is true, else, it is false. */
2516
+ static bool tcfdbforeachimpl(TCFDB *fdb, TCITER iter, void *op){
2517
+ bool err = false;
2518
+ uint64_t id = fdb->min;
2519
+ while(id > 0){
2520
+ int vsiz;
2521
+ const void *vbuf = tcfdbgetimpl(fdb, id, &vsiz);
2522
+ if(vbuf){
2523
+ char kbuf[TCNUMBUFSIZ];
2524
+ int ksiz = sprintf(kbuf, "%llu", (unsigned long long)id);
2525
+ if(!iter(kbuf, ksiz, vbuf, vsiz, op)) break;
2526
+ } else {
2527
+ tcfdbsetecode(fdb, TCEMISC, __FILE__, __LINE__, __func__);
2528
+ err = true;
2529
+ }
2530
+ id = tcfdbnextid(fdb, id);
2531
+ }
2532
+ return !err;
2533
+ }
2534
+
2535
+
2536
+ /* Lock a method of the fixed-length database object.
2537
+ `fdb' specifies the fixed-length database object.
2538
+ `wr' specifies whether the lock is writer or not.
2539
+ If successful, the return value is true, else, it is false. */
2540
+ static bool tcfdblockmethod(TCFDB *fdb, bool wr){
2541
+ assert(fdb);
2542
+ if(wr ? pthread_rwlock_wrlock(fdb->mmtx) != 0 : pthread_rwlock_rdlock(fdb->mmtx) != 0){
2543
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2544
+ return false;
2545
+ }
2546
+ TCTESTYIELD();
2547
+ return true;
2548
+ }
2549
+
2550
+
2551
+ /* Unlock a method of the fixed-length database object.
2552
+ `fdb' specifies the fixed-length database object.
2553
+ If successful, the return value is true, else, it is false. */
2554
+ static bool tcfdbunlockmethod(TCFDB *fdb){
2555
+ assert(fdb);
2556
+ if(pthread_rwlock_unlock(fdb->mmtx) != 0){
2557
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2558
+ return false;
2559
+ }
2560
+ TCTESTYIELD();
2561
+ return true;
2562
+ }
2563
+
2564
+
2565
+ /* Lock the attributes of the fixed-length database object.
2566
+ `fdb' specifies the fixed-length database object.
2567
+ If successful, the return value is true, else, it is false. */
2568
+ static bool tcfdblockattr(TCFDB *fdb){
2569
+ assert(fdb);
2570
+ if(pthread_mutex_lock(fdb->amtx) != 0){
2571
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2572
+ return false;
2573
+ }
2574
+ TCTESTYIELD();
2575
+ return true;
2576
+ }
2577
+
2578
+
2579
+ /* Unlock the attributes of the fixed-length database object.
2580
+ `fdb' specifies the fixed-length database object.
2581
+ If successful, the return value is true, else, it is false. */
2582
+ static bool tcfdbunlockattr(TCFDB *fdb){
2583
+ assert(fdb);
2584
+ if(pthread_mutex_unlock(fdb->amtx) != 0){
2585
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2586
+ return false;
2587
+ }
2588
+ TCTESTYIELD();
2589
+ return true;
2590
+ }
2591
+
2592
+
2593
+ /* Lock a record of the fixed-length database object.
2594
+ `fdb' specifies the fixed-length database object.
2595
+ `wr' specifies whether the lock is writer or not.
2596
+ If successful, the return value is true, else, it is false. */
2597
+ static bool tcfdblockrecord(TCFDB *fdb, bool wr, uint64_t id){
2598
+ assert(fdb && id > 0);
2599
+ if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0 :
2600
+ pthread_rwlock_rdlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0){
2601
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2602
+ return false;
2603
+ }
2604
+ TCTESTYIELD();
2605
+ return true;
2606
+ }
2607
+
2608
+
2609
+ /* Unlock a record of the fixed-length database object.
2610
+ `fdb' specifies the fixed-length database object.
2611
+ If successful, the return value is true, else, it is false. */
2612
+ static bool tcfdbunlockrecord(TCFDB *fdb, uint64_t id){
2613
+ assert(fdb);
2614
+ if(pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + id % FDBRMTXNUM) != 0){
2615
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2616
+ return false;
2617
+ }
2618
+ TCTESTYIELD();
2619
+ return true;
2620
+ }
2621
+
2622
+
2623
+ /* Lock all records of the fixed-length database object.
2624
+ `fdb' specifies the fixed-length database object.
2625
+ `wr' specifies whether the lock is writer or not.
2626
+ If successful, the return value is true, else, it is false. */
2627
+ static bool tcfdblockallrecords(TCFDB *fdb, bool wr){
2628
+ assert(fdb);
2629
+ for(int i = 0; i < FDBRMTXNUM; i++){
2630
+ if(wr ? pthread_rwlock_wrlock((pthread_rwlock_t *)fdb->rmtxs + i) != 0 :
2631
+ pthread_rwlock_rdlock((pthread_rwlock_t *)fdb->rmtxs + i) != 0){
2632
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2633
+ while(--i >= 0){
2634
+ pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + i);
2635
+ }
2636
+ return false;
2637
+ }
2638
+ }
2639
+ TCTESTYIELD();
2640
+ return true;
2641
+ }
2642
+
2643
+
2644
+ /* Unlock all records of the fixed-length database object.
2645
+ `fdb' specifies the fixed-length database object.
2646
+ If successful, the return value is true, else, it is false. */
2647
+ static bool tcfdbunlockallrecords(TCFDB *fdb){
2648
+ assert(fdb);
2649
+ bool err = false;
2650
+ for(int i = FDBRMTXNUM - 1; i >= 0; i--){
2651
+ if(pthread_rwlock_unlock((pthread_rwlock_t *)fdb->rmtxs + i)) err = true;
2652
+ }
2653
+ TCTESTYIELD();
2654
+ if(err){
2655
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2656
+ return false;
2657
+ }
2658
+ return true;
2659
+ }
2660
+
2661
+
2662
+ /* Lock the write ahead logging file of the fixed-length database object.
2663
+ `fdb' specifies the fixed-length database object.
2664
+ If successful, the return value is true, else, it is false. */
2665
+ static bool tcfdblockwal(TCFDB *fdb){
2666
+ assert(fdb);
2667
+ if(pthread_mutex_lock(fdb->wmtx) != 0){
2668
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2669
+ return false;
2670
+ }
2671
+ TCTESTYIELD();
2672
+ return true;
2673
+ }
2674
+
2675
+
2676
+ /* Unlock the write ahead logging file of the fixed-length database object.
2677
+ `fdb' specifies the fixed-length database object.
2678
+ If successful, the return value is true, else, it is false. */
2679
+ static bool tcfdbunlockwal(TCFDB *fdb){
2680
+ assert(fdb);
2681
+ if(pthread_mutex_unlock(fdb->wmtx) != 0){
2682
+ tcfdbsetecode(fdb, TCETHREAD, __FILE__, __LINE__, __func__);
2683
+ return false;
2684
+ }
2685
+ TCTESTYIELD();
2686
+ return true;
2687
+ }
2688
+
2689
+
2690
+
2691
+ /*************************************************************************************************
2692
+ * debugging functions
2693
+ *************************************************************************************************/
2694
+
2695
+
2696
+ /* Print meta data of the header into the debugging output.
2697
+ `fdb' specifies the fixed-length database object. */
2698
+ void tcfdbprintmeta(TCFDB *fdb){
2699
+ assert(fdb);
2700
+ if(fdb->dbgfd < 0) return;
2701
+ int dbgfd = (fdb->dbgfd == UINT16_MAX) ? 1 : fdb->dbgfd;
2702
+ char buf[FDBIOBUFSIZ];
2703
+ char *wp = buf;
2704
+ wp += sprintf(wp, "META:");
2705
+ wp += sprintf(wp, " mmtx=%p", (void *)fdb->mmtx);
2706
+ wp += sprintf(wp, " amtx=%p", (void *)fdb->amtx);
2707
+ wp += sprintf(wp, " rmtxs=%p", (void *)fdb->rmtxs);
2708
+ wp += sprintf(wp, " tmtx=%p", (void *)fdb->tmtx);
2709
+ wp += sprintf(wp, " wmtx=%p", (void *)fdb->wmtx);
2710
+ wp += sprintf(wp, " eckey=%p", (void *)fdb->eckey);
2711
+ wp += sprintf(wp, " rpath=%s", fdb->rpath ? fdb->rpath : "-");
2712
+ wp += sprintf(wp, " type=%02X", fdb->type);
2713
+ wp += sprintf(wp, " flags=%02X", fdb->flags);
2714
+ wp += sprintf(wp, " width=%u", fdb->width);
2715
+ wp += sprintf(wp, " limsiz=%llu", (unsigned long long)fdb->limsiz);
2716
+ wp += sprintf(wp, " wsiz=%u", fdb->wsiz);
2717
+ wp += sprintf(wp, " rsiz=%u", fdb->rsiz);
2718
+ wp += sprintf(wp, " limid=%llu", (unsigned long long)fdb->limid);
2719
+ wp += sprintf(wp, " path=%s", fdb->path ? fdb->path : "-");
2720
+ wp += sprintf(wp, " fd=%d", fdb->fd);
2721
+ wp += sprintf(wp, " omode=%u", fdb->omode);
2722
+ wp += sprintf(wp, " rnum=%llu", (unsigned long long)fdb->rnum);
2723
+ wp += sprintf(wp, " fsiz=%llu", (unsigned long long)fdb->fsiz);
2724
+ wp += sprintf(wp, " min=%llu", (unsigned long long)fdb->min);
2725
+ wp += sprintf(wp, " max=%llu", (unsigned long long)fdb->max);
2726
+ wp += sprintf(wp, " iter=%llu", (unsigned long long)fdb->iter);
2727
+ wp += sprintf(wp, " map=%p", (void *)fdb->map);
2728
+ wp += sprintf(wp, " array=%p", (void *)fdb->array);
2729
+ wp += sprintf(wp, " ecode=%d", fdb->ecode);
2730
+ wp += sprintf(wp, " fatal=%u", fdb->fatal);
2731
+ wp += sprintf(wp, " inode=%llu", (unsigned long long)fdb->inode);
2732
+ wp += sprintf(wp, " mtime=%llu", (unsigned long long)fdb->mtime);
2733
+ wp += sprintf(wp, " tran=%d", fdb->tran);
2734
+ wp += sprintf(wp, " walfd=%d", fdb->walfd);
2735
+ wp += sprintf(wp, " walend=%llu", (unsigned long long)fdb->walend);
2736
+ wp += sprintf(wp, " dbgfd=%d", fdb->dbgfd);
2737
+ wp += sprintf(wp, " cnt_writerec=%lld", (long long)fdb->cnt_writerec);
2738
+ wp += sprintf(wp, " cnt_readrec=%lld", (long long)fdb->cnt_readrec);
2739
+ wp += sprintf(wp, " cnt_truncfile=%lld", (long long)fdb->cnt_truncfile);
2740
+ *(wp++) = '\n';
2741
+ tcwrite(dbgfd, buf, wp - buf);
2742
+ }
2743
+
2744
+
2745
+
2746
+ // END OF FILE