tdb.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #include "private.h"
  2. #include <ccan/asprintf/asprintf.h>
  3. #include <stdarg.h>
  4. static enum TDB_ERROR update_rec_hdr(struct tdb_context *tdb,
  5. tdb_off_t off,
  6. tdb_len_t keylen,
  7. tdb_len_t datalen,
  8. struct tdb_used_record *rec,
  9. uint64_t h)
  10. {
  11. uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
  12. enum TDB_ERROR ecode;
  13. ecode = set_header(tdb, rec, TDB_USED_MAGIC, keylen, datalen,
  14. keylen + dataroom, h);
  15. if (ecode == TDB_SUCCESS) {
  16. ecode = tdb_write_convert(tdb, off, rec, sizeof(*rec));
  17. }
  18. return ecode;
  19. }
  20. static enum TDB_ERROR replace_data(struct tdb_context *tdb,
  21. struct hash_info *h,
  22. struct tdb_data key, struct tdb_data dbuf,
  23. tdb_off_t old_off, tdb_len_t old_room,
  24. bool growing)
  25. {
  26. tdb_off_t new_off;
  27. enum TDB_ERROR ecode;
  28. /* Allocate a new record. */
  29. new_off = alloc(tdb, key.dsize, dbuf.dsize, h->h, TDB_USED_MAGIC,
  30. growing);
  31. if (TDB_OFF_IS_ERR(new_off)) {
  32. return new_off;
  33. }
  34. /* We didn't like the existing one: remove it. */
  35. if (old_off) {
  36. add_stat(tdb, frees, 1);
  37. ecode = add_free_record(tdb, old_off,
  38. sizeof(struct tdb_used_record)
  39. + key.dsize + old_room);
  40. if (ecode == TDB_SUCCESS)
  41. ecode = replace_in_hash(tdb, h, new_off);
  42. } else {
  43. ecode = add_to_hash(tdb, h, new_off);
  44. }
  45. if (ecode != TDB_SUCCESS) {
  46. return ecode;
  47. }
  48. new_off += sizeof(struct tdb_used_record);
  49. ecode = tdb->methods->twrite(tdb, new_off, key.dptr, key.dsize);
  50. if (ecode != TDB_SUCCESS) {
  51. return ecode;
  52. }
  53. new_off += key.dsize;
  54. ecode = tdb->methods->twrite(tdb, new_off, dbuf.dptr, dbuf.dsize);
  55. if (ecode != TDB_SUCCESS) {
  56. return ecode;
  57. }
  58. if (tdb->flags & TDB_SEQNUM)
  59. tdb_inc_seqnum(tdb);
  60. return TDB_SUCCESS;
  61. }
  62. static enum TDB_ERROR update_data(struct tdb_context *tdb,
  63. tdb_off_t off,
  64. struct tdb_data dbuf,
  65. tdb_len_t extra)
  66. {
  67. enum TDB_ERROR ecode;
  68. ecode = tdb->methods->twrite(tdb, off, dbuf.dptr, dbuf.dsize);
  69. if (ecode == TDB_SUCCESS && extra) {
  70. /* Put a zero in; future versions may append other data. */
  71. ecode = tdb->methods->twrite(tdb, off + dbuf.dsize, "", 1);
  72. }
  73. if (tdb->flags & TDB_SEQNUM)
  74. tdb_inc_seqnum(tdb);
  75. return ecode;
  76. }
  77. enum TDB_ERROR tdb_store(struct tdb_context *tdb,
  78. struct tdb_data key, struct tdb_data dbuf, int flag)
  79. {
  80. struct hash_info h;
  81. tdb_off_t off;
  82. tdb_len_t old_room = 0;
  83. struct tdb_used_record rec;
  84. enum TDB_ERROR ecode;
  85. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  86. if (TDB_OFF_IS_ERR(off)) {
  87. return tdb->last_error = off;
  88. }
  89. /* Now we have lock on this hash bucket. */
  90. if (flag == TDB_INSERT) {
  91. if (off) {
  92. ecode = TDB_ERR_EXISTS;
  93. goto out;
  94. }
  95. } else {
  96. if (off) {
  97. old_room = rec_data_length(&rec)
  98. + rec_extra_padding(&rec);
  99. if (old_room >= dbuf.dsize) {
  100. /* Can modify in-place. Easy! */
  101. ecode = update_rec_hdr(tdb, off,
  102. key.dsize, dbuf.dsize,
  103. &rec, h.h);
  104. if (ecode != TDB_SUCCESS) {
  105. goto out;
  106. }
  107. ecode = update_data(tdb,
  108. off + sizeof(rec)
  109. + key.dsize, dbuf,
  110. old_room - dbuf.dsize);
  111. if (ecode != TDB_SUCCESS) {
  112. goto out;
  113. }
  114. tdb_unlock_hashes(tdb, h.hlock_start,
  115. h.hlock_range, F_WRLCK);
  116. return tdb->last_error = TDB_SUCCESS;
  117. }
  118. } else {
  119. if (flag == TDB_MODIFY) {
  120. /* if the record doesn't exist and we
  121. are in TDB_MODIFY mode then we should fail
  122. the store */
  123. ecode = TDB_ERR_NOEXIST;
  124. goto out;
  125. }
  126. }
  127. }
  128. /* If we didn't use the old record, this implies we're growing. */
  129. ecode = replace_data(tdb, &h, key, dbuf, off, old_room, off);
  130. out:
  131. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  132. return tdb->last_error = ecode;
  133. }
  134. enum TDB_ERROR tdb_append(struct tdb_context *tdb,
  135. struct tdb_data key, struct tdb_data dbuf)
  136. {
  137. struct hash_info h;
  138. tdb_off_t off;
  139. struct tdb_used_record rec;
  140. tdb_len_t old_room = 0, old_dlen;
  141. unsigned char *newdata;
  142. struct tdb_data new_dbuf;
  143. enum TDB_ERROR ecode;
  144. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  145. if (TDB_OFF_IS_ERR(off)) {
  146. return tdb->last_error = off;
  147. }
  148. if (off) {
  149. old_dlen = rec_data_length(&rec);
  150. old_room = old_dlen + rec_extra_padding(&rec);
  151. /* Fast path: can append in place. */
  152. if (rec_extra_padding(&rec) >= dbuf.dsize) {
  153. ecode = update_rec_hdr(tdb, off, key.dsize,
  154. old_dlen + dbuf.dsize, &rec,
  155. h.h);
  156. if (ecode != TDB_SUCCESS) {
  157. goto out;
  158. }
  159. off += sizeof(rec) + key.dsize + old_dlen;
  160. ecode = update_data(tdb, off, dbuf,
  161. rec_extra_padding(&rec));
  162. goto out;
  163. }
  164. /* Slow path. */
  165. newdata = malloc(key.dsize + old_dlen + dbuf.dsize);
  166. if (!newdata) {
  167. ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
  168. "tdb_append:"
  169. " failed to allocate %zu bytes",
  170. (size_t)(key.dsize + old_dlen
  171. + dbuf.dsize));
  172. goto out;
  173. }
  174. ecode = tdb->methods->tread(tdb, off + sizeof(rec) + key.dsize,
  175. newdata, old_dlen);
  176. if (ecode != TDB_SUCCESS) {
  177. goto out_free_newdata;
  178. }
  179. memcpy(newdata + old_dlen, dbuf.dptr, dbuf.dsize);
  180. new_dbuf.dptr = newdata;
  181. new_dbuf.dsize = old_dlen + dbuf.dsize;
  182. } else {
  183. newdata = NULL;
  184. new_dbuf = dbuf;
  185. }
  186. /* If they're using tdb_append(), it implies they're growing record. */
  187. ecode = replace_data(tdb, &h, key, new_dbuf, off, old_room, true);
  188. out_free_newdata:
  189. free(newdata);
  190. out:
  191. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  192. return tdb->last_error = ecode;
  193. }
  194. enum TDB_ERROR tdb_fetch(struct tdb_context *tdb, struct tdb_data key,
  195. struct tdb_data *data)
  196. {
  197. tdb_off_t off;
  198. struct tdb_used_record rec;
  199. struct hash_info h;
  200. enum TDB_ERROR ecode;
  201. off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
  202. if (TDB_OFF_IS_ERR(off)) {
  203. return tdb->last_error = off;
  204. }
  205. if (!off) {
  206. ecode = TDB_ERR_NOEXIST;
  207. } else {
  208. data->dsize = rec_data_length(&rec);
  209. data->dptr = tdb_alloc_read(tdb, off + sizeof(rec) + key.dsize,
  210. data->dsize);
  211. if (TDB_PTR_IS_ERR(data->dptr)) {
  212. ecode = TDB_PTR_ERR(data->dptr);
  213. } else
  214. ecode = TDB_SUCCESS;
  215. }
  216. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
  217. return tdb->last_error = ecode;
  218. }
  219. bool tdb_exists(struct tdb_context *tdb, TDB_DATA key)
  220. {
  221. tdb_off_t off;
  222. struct tdb_used_record rec;
  223. struct hash_info h;
  224. off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
  225. if (TDB_OFF_IS_ERR(off)) {
  226. tdb->last_error = off;
  227. return false;
  228. }
  229. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
  230. tdb->last_error = TDB_SUCCESS;
  231. return off ? true : false;
  232. }
  233. enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key)
  234. {
  235. tdb_off_t off;
  236. struct tdb_used_record rec;
  237. struct hash_info h;
  238. enum TDB_ERROR ecode;
  239. off = find_and_lock(tdb, key, F_WRLCK, &h, &rec, NULL);
  240. if (TDB_OFF_IS_ERR(off)) {
  241. return tdb->last_error = off;
  242. }
  243. if (!off) {
  244. ecode = TDB_ERR_NOEXIST;
  245. goto unlock;
  246. }
  247. ecode = delete_from_hash(tdb, &h);
  248. if (ecode != TDB_SUCCESS) {
  249. goto unlock;
  250. }
  251. /* Free the deleted entry. */
  252. add_stat(tdb, frees, 1);
  253. ecode = add_free_record(tdb, off,
  254. sizeof(struct tdb_used_record)
  255. + rec_key_length(&rec)
  256. + rec_data_length(&rec)
  257. + rec_extra_padding(&rec));
  258. if (tdb->flags & TDB_SEQNUM)
  259. tdb_inc_seqnum(tdb);
  260. unlock:
  261. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_WRLCK);
  262. return tdb->last_error = ecode;
  263. }
  264. unsigned int tdb_get_flags(struct tdb_context *tdb)
  265. {
  266. return tdb->flags;
  267. }
  268. void tdb_add_flag(struct tdb_context *tdb, unsigned flag)
  269. {
  270. if (tdb->flags & TDB_INTERNAL) {
  271. tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
  272. TDB_LOG_USE_ERROR,
  273. "tdb_add_flag: internal db");
  274. return;
  275. }
  276. switch (flag) {
  277. case TDB_NOLOCK:
  278. tdb->flags |= TDB_NOLOCK;
  279. break;
  280. case TDB_NOMMAP:
  281. tdb->flags |= TDB_NOMMAP;
  282. tdb_munmap(tdb->file);
  283. break;
  284. case TDB_NOSYNC:
  285. tdb->flags |= TDB_NOSYNC;
  286. break;
  287. case TDB_SEQNUM:
  288. tdb->flags |= TDB_SEQNUM;
  289. break;
  290. default:
  291. tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
  292. TDB_LOG_USE_ERROR,
  293. "tdb_add_flag: Unknown flag %u",
  294. flag);
  295. }
  296. }
  297. void tdb_remove_flag(struct tdb_context *tdb, unsigned flag)
  298. {
  299. if (tdb->flags & TDB_INTERNAL) {
  300. tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
  301. TDB_LOG_USE_ERROR,
  302. "tdb_remove_flag: internal db");
  303. return;
  304. }
  305. switch (flag) {
  306. case TDB_NOLOCK:
  307. tdb->flags &= ~TDB_NOLOCK;
  308. break;
  309. case TDB_NOMMAP:
  310. tdb->flags &= ~TDB_NOMMAP;
  311. tdb_mmap(tdb);
  312. break;
  313. case TDB_NOSYNC:
  314. tdb->flags &= ~TDB_NOSYNC;
  315. break;
  316. case TDB_SEQNUM:
  317. tdb->flags &= ~TDB_SEQNUM;
  318. break;
  319. default:
  320. tdb->last_error = tdb_logerr(tdb, TDB_ERR_EINVAL,
  321. TDB_LOG_USE_ERROR,
  322. "tdb_remove_flag: Unknown flag %u",
  323. flag);
  324. }
  325. }
  326. const char *tdb_errorstr(enum TDB_ERROR ecode)
  327. {
  328. /* Gcc warns if you miss a case in the switch, so use that. */
  329. switch (ecode) {
  330. case TDB_SUCCESS: return "Success";
  331. case TDB_ERR_CORRUPT: return "Corrupt database";
  332. case TDB_ERR_IO: return "IO Error";
  333. case TDB_ERR_LOCK: return "Locking error";
  334. case TDB_ERR_OOM: return "Out of memory";
  335. case TDB_ERR_EXISTS: return "Record exists";
  336. case TDB_ERR_EINVAL: return "Invalid parameter";
  337. case TDB_ERR_NOEXIST: return "Record does not exist";
  338. case TDB_ERR_RDONLY: return "write not permitted";
  339. }
  340. return "Invalid error code";
  341. }
  342. enum TDB_ERROR tdb_error(struct tdb_context *tdb)
  343. {
  344. return tdb->last_error;
  345. }
  346. enum TDB_ERROR COLD tdb_logerr(struct tdb_context *tdb,
  347. enum TDB_ERROR ecode,
  348. enum tdb_log_level level,
  349. const char *fmt, ...)
  350. {
  351. char *message;
  352. va_list ap;
  353. size_t len;
  354. /* tdb_open paths care about errno, so save it. */
  355. int saved_errno = errno;
  356. if (!tdb->log_fn)
  357. return ecode;
  358. va_start(ap, fmt);
  359. len = vasprintf(&message, fmt, ap);
  360. va_end(ap);
  361. if (len < 0) {
  362. tdb->log_fn(tdb, TDB_LOG_ERROR,
  363. "out of memory formatting message:", tdb->log_data);
  364. tdb->log_fn(tdb, level, fmt, tdb->log_data);
  365. } else {
  366. tdb->log_fn(tdb, level, message, tdb->log_data);
  367. free(message);
  368. }
  369. errno = saved_errno;
  370. return ecode;
  371. }
  372. enum TDB_ERROR tdb_parse_record_(struct tdb_context *tdb,
  373. TDB_DATA key,
  374. enum TDB_ERROR (*parse)(TDB_DATA k,
  375. TDB_DATA d,
  376. void *data),
  377. void *data)
  378. {
  379. tdb_off_t off;
  380. struct tdb_used_record rec;
  381. struct hash_info h;
  382. enum TDB_ERROR ecode;
  383. off = find_and_lock(tdb, key, F_RDLCK, &h, &rec, NULL);
  384. if (TDB_OFF_IS_ERR(off)) {
  385. return tdb->last_error = off;
  386. }
  387. if (!off) {
  388. ecode = TDB_ERR_NOEXIST;
  389. } else {
  390. const void *dptr;
  391. dptr = tdb_access_read(tdb, off + sizeof(rec) + key.dsize,
  392. rec_data_length(&rec), false);
  393. if (TDB_PTR_IS_ERR(dptr)) {
  394. ecode = TDB_PTR_ERR(dptr);
  395. } else {
  396. TDB_DATA d = tdb_mkdata(dptr, rec_data_length(&rec));
  397. ecode = parse(key, d, data);
  398. tdb_access_release(tdb, dptr);
  399. }
  400. }
  401. tdb_unlock_hashes(tdb, h.hlock_start, h.hlock_range, F_RDLCK);
  402. return tdb->last_error = ecode;
  403. }
  404. const char *tdb_name(const struct tdb_context *tdb)
  405. {
  406. return tdb->name;
  407. }
  408. int64_t tdb_get_seqnum(struct tdb_context *tdb)
  409. {
  410. tdb_off_t off = tdb_read_off(tdb, offsetof(struct tdb_header, seqnum));
  411. if (TDB_OFF_IS_ERR(off))
  412. tdb->last_error = off;
  413. else
  414. tdb->last_error = TDB_SUCCESS;
  415. return off;
  416. }
  417. int tdb_fd(const struct tdb_context *tdb)
  418. {
  419. return tdb->file->fd;
  420. }