MemoryMappingTest.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright 2013-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <cstdlib>
  17. #include <folly/FileUtil.h>
  18. #include <folly/Random.h>
  19. #include <folly/portability/GTest.h>
  20. #include <folly/portability/SysMman.h>
  21. #include <folly/system/MemoryMapping.h>
  22. static constexpr double kSomeDouble = 3.14;
  23. namespace folly {
  24. TEST(MemoryMapping, Basic) {
  25. File f = File::temporary();
  26. {
  27. MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
  28. double* d = m.asWritableRange<double>().data();
  29. *d = 37 * kSomeDouble;
  30. }
  31. {
  32. MemoryMapping m(File(f.fd()), 0, 3);
  33. EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
  34. }
  35. {
  36. MemoryMapping m(File(f.fd()), 0, sizeof(double));
  37. const double* d = m.asRange<double>().data();
  38. EXPECT_EQ(*d, 37 * kSomeDouble);
  39. }
  40. }
  41. TEST(MemoryMapping, Move) {
  42. File f = File::temporary();
  43. {
  44. MemoryMapping m(
  45. File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
  46. double* d = m.asWritableRange<double>().data();
  47. d[0] = 37 * kSomeDouble;
  48. MemoryMapping m2(std::move(m));
  49. double* d2 = m2.asWritableRange<double>().data();
  50. d2[1] = 39 * kSomeDouble;
  51. }
  52. {
  53. MemoryMapping m(File(f.fd()), 0, sizeof(double));
  54. const double* d = m.asRange<double>().data();
  55. EXPECT_EQ(d[0], 37 * kSomeDouble);
  56. MemoryMapping m2(std::move(m));
  57. const double* d2 = m2.asRange<double>().data();
  58. EXPECT_EQ(d2[1], 39 * kSomeDouble);
  59. }
  60. }
  61. TEST(MemoryMapping, DoublyMapped) {
  62. File f = File::temporary();
  63. // two mappings of the same memory, different addresses.
  64. MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
  65. MemoryMapping mr(File(f.fd()), 0, sizeof(double));
  66. double* dw = mw.asWritableRange<double>().data();
  67. const double* dr = mr.asRange<double>().data();
  68. // Show that it's truly the same value, even though the pointers differ
  69. EXPECT_NE(dw, dr);
  70. *dw = 42 * kSomeDouble;
  71. EXPECT_EQ(*dr, 42 * kSomeDouble);
  72. *dw = 43 * kSomeDouble;
  73. EXPECT_EQ(*dr, 43 * kSomeDouble);
  74. }
  75. namespace {
  76. void writeStringToFileOrDie(const std::string& str, int fd) {
  77. const char* b = str.c_str();
  78. size_t count = str.size();
  79. ssize_t total_bytes = 0;
  80. ssize_t r;
  81. do {
  82. r = write(fd, b, count);
  83. if (r == -1) {
  84. if (errno == EINTR) {
  85. continue;
  86. }
  87. PCHECK(r) << "write";
  88. }
  89. total_bytes += r;
  90. b += r;
  91. count -= r;
  92. } while (r != 0 && count);
  93. }
  94. } // namespace
  95. TEST(MemoryMapping, Simple) {
  96. File f = File::temporary();
  97. writeStringToFileOrDie("hello", f.fd());
  98. {
  99. MemoryMapping m(File(f.fd()));
  100. EXPECT_EQ("hello", m.data());
  101. }
  102. {
  103. MemoryMapping m(File(f.fd()), 1, 2);
  104. EXPECT_EQ("el", m.data());
  105. }
  106. }
  107. TEST(MemoryMapping, LargeFile) {
  108. std::string fileData;
  109. size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
  110. fileData.reserve(fileSize);
  111. for (size_t i = 0; i < fileSize; i++) {
  112. fileData.push_back(0xff & Random::rand32());
  113. }
  114. File f = File::temporary();
  115. writeStringToFileOrDie(fileData, f.fd());
  116. {
  117. MemoryMapping m(File(f.fd()));
  118. EXPECT_EQ(fileData, m.data());
  119. }
  120. {
  121. size_t size = sysconf(_SC_PAGESIZE) * 2;
  122. StringPiece s(fileData.data() + 9, size - 9);
  123. MemoryMapping m(File(f.fd()), 9, size - 9);
  124. EXPECT_EQ(s.toString(), m.data());
  125. }
  126. }
  127. TEST(MemoryMapping, ZeroLength) {
  128. File f = File::temporary();
  129. MemoryMapping m(File(f.fd()));
  130. EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
  131. EXPECT_TRUE(m.mlocked());
  132. EXPECT_EQ(0, m.data().size());
  133. }
  134. TEST(MemoryMapping, Advise) {
  135. File f = File::temporary();
  136. size_t kPageSize = 4096;
  137. size_t size = kPageSize + 10; // unaligned file size
  138. PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
  139. MemoryMapping m(File(f.fd()));
  140. // NOTE: advise crashes on bad input.
  141. m.advise(MADV_NORMAL, 0, kPageSize);
  142. m.advise(MADV_NORMAL, 1, kPageSize);
  143. m.advise(MADV_NORMAL, 0, 2);
  144. m.advise(MADV_NORMAL, 1, 2);
  145. m.advise(MADV_NORMAL, kPageSize, 0);
  146. m.advise(MADV_NORMAL, kPageSize, 1);
  147. m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
  148. auto off = kPageSize + 1;
  149. m.advise(MADV_NORMAL, off, size - off);
  150. EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
  151. }
  152. } // namespace folly