2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/FileUtil.h>
20 #include <folly/MemoryMapping.h>
21 #include <folly/Random.h>
22 #include <folly/portability/SysMman.h>
24 #include <gtest/gtest.h>
26 static constexpr double kSomeDouble = 3.14;
30 TEST(MemoryMapping, Basic) {
31 File f = File::temporary();
33 MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
34 double* d = m.asWritableRange<double>().data();
35 *d = 37 * kSomeDouble;
38 MemoryMapping m(File(f.fd()), 0, 3);
39 EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
42 MemoryMapping m(File(f.fd()), 0, sizeof(double));
43 const double* d = m.asRange<double>().data();
44 EXPECT_EQ(*d, 37 * kSomeDouble);
48 TEST(MemoryMapping, Move) {
49 File f = File::temporary();
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;
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);
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));
75 double* dw = mw.asWritableRange<double>().data();
76 const double* dr = mr.asRange<double>().data();
78 // Show that it's truly the same value, even though the pointers differ
80 *dw = 42 * kSomeDouble;
81 EXPECT_EQ(*dr, 42 * kSomeDouble);
82 *dw = 43 * kSomeDouble;
83 EXPECT_EQ(*dr, 43 * kSomeDouble);
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;
94 r = write(fd, b, count);
105 } while (r != 0 && count);
108 } // anonymous namespace
110 TEST(MemoryMapping, Simple) {
111 File f = File::temporary();
112 writeStringToFileOrDie("hello", f.fd());
115 MemoryMapping m(File(f.fd()));
116 EXPECT_EQ("hello", m.data());
119 MemoryMapping m(File(f.fd()), 1, 2);
120 EXPECT_EQ("el", m.data());
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());
132 File f = File::temporary();
133 writeStringToFileOrDie(fileData, f.fd());
136 MemoryMapping m(File(f.fd()));
137 EXPECT_EQ(fileData, m.data());
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());
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());
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;
161 MemoryMapping m(File(f.fd()));
163 // NOTE: advise crashes on bad input.
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);
170 m.advise(MADV_NORMAL, kPageSize, 0);
171 m.advise(MADV_NORMAL, kPageSize, 1);
172 m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
174 auto off = kPageSize + 1;
175 m.advise(MADV_NORMAL, off, size - off);
177 EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");