run-56-open-during-transaction.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "../private.h"
  2. #include <unistd.h>
  3. #include "lock-tracking.h"
  4. static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
  5. static ssize_t write_check(int fd, const void *buf, size_t count);
  6. static int ftruncate_check(int fd, off_t length);
  7. #define pwrite pwrite_check
  8. #define write write_check
  9. #define fcntl fcntl_with_lockcheck
  10. #define ftruncate ftruncate_check
  11. #include "ntdb-source.h"
  12. #include "tap-interface.h"
  13. #include <stdlib.h>
  14. #include <stdbool.h>
  15. #include <stdarg.h>
  16. #include "external-agent.h"
  17. #include "logging.h"
  18. #include "helprun-external-agent.h"
  19. static struct agent *agent;
  20. static bool opened;
  21. static int errors = 0;
  22. #define TEST_DBNAME "run-56-open-during-transaction.ntdb"
  23. #undef write
  24. #undef pwrite
  25. #undef fcntl
  26. #undef ftruncate
  27. static bool is_same(const char *snapshot, const char *latest, off_t len)
  28. {
  29. unsigned i;
  30. for (i = 0; i < len; i++) {
  31. if (snapshot[i] != latest[i])
  32. return false;
  33. }
  34. return true;
  35. }
  36. static bool compare_file(int fd, const char *snapshot, off_t snapshot_len)
  37. {
  38. char *contents;
  39. bool ret;
  40. /* over-length read serves as length check. */
  41. contents = malloc(snapshot_len+1);
  42. ret = pread(fd, contents, snapshot_len+1, 0) == snapshot_len
  43. && is_same(snapshot, contents, snapshot_len);
  44. free(contents);
  45. return ret;
  46. }
  47. static void check_file_intact(int fd)
  48. {
  49. enum agent_return ret;
  50. struct stat st;
  51. char *contents;
  52. fstat(fd, &st);
  53. contents = malloc(st.st_size);
  54. if (pread(fd, contents, st.st_size, 0) != st.st_size) {
  55. diag("Read fail");
  56. errors++;
  57. return;
  58. }
  59. /* Ask agent to open file. */
  60. ret = external_agent_operation(agent, OPEN, TEST_DBNAME);
  61. /* It's OK to open it, but it must not have changed! */
  62. if (!compare_file(fd, contents, st.st_size)) {
  63. diag("Agent changed file after opening %s",
  64. agent_return_name(ret));
  65. errors++;
  66. }
  67. if (ret == SUCCESS) {
  68. ret = external_agent_operation(agent, CLOSE, NULL);
  69. if (ret != SUCCESS) {
  70. diag("Agent failed to close ntdb: %s",
  71. agent_return_name(ret));
  72. errors++;
  73. }
  74. } else if (ret != WOULD_HAVE_BLOCKED) {
  75. diag("Agent opening file gave %s",
  76. agent_return_name(ret));
  77. errors++;
  78. }
  79. free(contents);
  80. }
  81. static void after_unlock(int fd)
  82. {
  83. if (opened)
  84. check_file_intact(fd);
  85. }
  86. static ssize_t pwrite_check(int fd,
  87. const void *buf, size_t count, off_t offset)
  88. {
  89. if (opened)
  90. check_file_intact(fd);
  91. return pwrite(fd, buf, count, offset);
  92. }
  93. static ssize_t write_check(int fd, const void *buf, size_t count)
  94. {
  95. if (opened)
  96. check_file_intact(fd);
  97. return write(fd, buf, count);
  98. }
  99. static int ftruncate_check(int fd, off_t length)
  100. {
  101. if (opened)
  102. check_file_intact(fd);
  103. return ftruncate(fd, length);
  104. }
  105. int main(int argc, char *argv[])
  106. {
  107. const int flags[] = { NTDB_DEFAULT, NTDB_NOMMAP,
  108. NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT };
  109. int i;
  110. struct ntdb_context *ntdb;
  111. NTDB_DATA key, data;
  112. plan_tests(sizeof(flags)/sizeof(flags[0]) * 5);
  113. agent = prepare_external_agent();
  114. if (!agent)
  115. err(1, "preparing agent");
  116. unlock_callback = after_unlock;
  117. for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) {
  118. diag("Test with %s and %s\n",
  119. (flags[i] & NTDB_CONVERT) ? "CONVERT" : "DEFAULT",
  120. (flags[i] & NTDB_NOMMAP) ? "no mmap" : "mmap");
  121. unlink(TEST_DBNAME);
  122. ntdb = ntdb_open(TEST_DBNAME, flags[i]|MAYBE_NOSYNC,
  123. O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
  124. ok1(ntdb);
  125. opened = true;
  126. ok1(ntdb_transaction_start(ntdb) == 0);
  127. key = ntdb_mkdata("hi", strlen("hi"));
  128. data = ntdb_mkdata("world", strlen("world"));
  129. ok1(ntdb_store(ntdb, key, data, NTDB_INSERT) == 0);
  130. ok1(ntdb_transaction_commit(ntdb) == 0);
  131. ok(!errors, "We had %u open errors", errors);
  132. opened = false;
  133. ntdb_close(ntdb);
  134. }
  135. return exit_status();
  136. }