Use folly::Random and ensure M_PI is defined
[folly.git] / folly / test / MemoryMappingTest.cpp
1 /*
2  * Copyright 2016 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
17 #include <cstdlib>
18
19 #include <folly/FileUtil.h>
20 #include <folly/MemoryMapping.h>
21 #include <folly/Random.h>
22 #include <folly/portability/SysMman.h>
23
24 #include <gtest/gtest.h>
25
26 static constexpr double kSomeDouble = 3.14;
27
28 namespace folly {
29
30 TEST(MemoryMapping, Basic) {
31   File f = File::temporary();
32   {
33     MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
34     double* d = m.asWritableRange<double>().data();
35     *d = 37 * kSomeDouble;
36   }
37   {
38     MemoryMapping m(File(f.fd()), 0, 3);
39     EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
40   }
41   {
42     MemoryMapping m(File(f.fd()), 0, sizeof(double));
43     const double* d = m.asRange<double>().data();
44     EXPECT_EQ(*d, 37 * kSomeDouble);
45   }
46 }
47
48 TEST(MemoryMapping, Move) {
49   File f = File::temporary();
50   {
51     MemoryMapping m(
52         File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
53     double* d = m.asWritableRange<double>().data();
54     d[0] = 37 * kSomeDouble;
55     MemoryMapping m2(std::move(m));
56     double* d2 = m2.asWritableRange<double>().data();
57     d2[1] = 39 * kSomeDouble;
58   }
59   {
60     MemoryMapping m(File(f.fd()), 0, sizeof(double));
61     const double* d = m.asRange<double>().data();
62     EXPECT_EQ(d[0], 37 * kSomeDouble);
63     MemoryMapping m2(std::move(m));
64     const double* d2 = m2.asRange<double>().data();
65     EXPECT_EQ(d2[1], 39 * kSomeDouble);
66   }
67 }
68
69 TEST(MemoryMapping, DoublyMapped) {
70   File f = File::temporary();
71   // two mappings of the same memory, different addresses.
72   MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
73   MemoryMapping mr(File(f.fd()), 0, sizeof(double));
74
75   double* dw = mw.asWritableRange<double>().data();
76   const double* dr = mr.asRange<double>().data();
77
78   // Show that it's truly the same value, even though the pointers differ
79   EXPECT_NE(dw, dr);
80   *dw = 42 * kSomeDouble;
81   EXPECT_EQ(*dr, 42 * kSomeDouble);
82   *dw = 43 * kSomeDouble;
83   EXPECT_EQ(*dr, 43 * kSomeDouble);
84 }
85
86 namespace {
87
88 void writeStringToFileOrDie(const std::string& str, int fd) {
89   const char* b = str.c_str();
90   size_t count = str.size();
91   ssize_t total_bytes = 0;
92   ssize_t r;
93   do {
94     r = write(fd, b, count);
95     if (r == -1) {
96       if (errno == EINTR) {
97         continue;
98       }
99       PCHECK(r) << "write";
100     }
101
102     total_bytes += r;
103     b += r;
104     count -= r;
105   } while (r != 0 && count);
106 }
107
108 }  // anonymous namespace
109
110 TEST(MemoryMapping, Simple) {
111   File f = File::temporary();
112   writeStringToFileOrDie("hello", f.fd());
113
114   {
115     MemoryMapping m(File(f.fd()));
116     EXPECT_EQ("hello", m.data());
117   }
118   {
119     MemoryMapping m(File(f.fd()), 1, 2);
120     EXPECT_EQ("el", m.data());
121   }
122 }
123
124 TEST(MemoryMapping, LargeFile) {
125   std::string fileData;
126   size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
127   fileData.reserve(fileSize);
128   for (size_t i = 0; i < fileSize; i++) {
129     fileData.push_back(0xff & Random::rand32());
130   }
131
132   File f = File::temporary();
133   writeStringToFileOrDie(fileData, f.fd());
134
135   {
136     MemoryMapping m(File(f.fd()));
137     EXPECT_EQ(fileData, m.data());
138   }
139   {
140     size_t size = sysconf(_SC_PAGESIZE) * 2;
141     StringPiece s(fileData.data() + 9, size - 9);
142     MemoryMapping m(File(f.fd()), 9, size - 9);
143     EXPECT_EQ(s.toString(), m.data());
144   }
145 }
146
147 TEST(MemoryMapping, ZeroLength) {
148   File f = File::temporary();
149   MemoryMapping m(File(f.fd()));
150   EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
151   EXPECT_TRUE(m.mlocked());
152   EXPECT_EQ(0, m.data().size());
153 }
154
155 TEST(MemoryMapping, Advise) {
156   File f = File::temporary();
157   size_t kPageSize = 4096;
158   size_t size = kPageSize + 10;  // unaligned file size
159   PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
160
161   MemoryMapping m(File(f.fd()));
162
163   // NOTE: advise crashes on bad input.
164
165   m.advise(MADV_NORMAL, 0, kPageSize);
166   m.advise(MADV_NORMAL, 1, kPageSize);
167   m.advise(MADV_NORMAL, 0, 2);
168   m.advise(MADV_NORMAL, 1, 2);
169
170   m.advise(MADV_NORMAL, kPageSize, 0);
171   m.advise(MADV_NORMAL, kPageSize, 1);
172   m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
173
174   auto off = kPageSize + 1;
175   m.advise(MADV_NORMAL, off, size - off);
176
177   EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
178 }
179
180 } // namespace folly