std::move-able MemoryMapping
[folly.git] / folly / test / MemoryMappingTest.cpp
1 /*
2  * Copyright 2014 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 #include <gtest/gtest.h>
19 #include "folly/MemoryMapping.h"
20
21 namespace folly {
22
23 TEST(MemoryMapping, Basic) {
24   File f = File::temporary();
25   {
26     WritableMemoryMapping m(File(f.fd()), 0, sizeof(double));
27     double volatile* d = m.asWritableRange<double>().data();
28     *d = 37 * M_PI;
29   }
30   {
31     MemoryMapping m(File(f.fd()), 0, 3);
32     EXPECT_EQ(0, m.asRange<int>().size()); //not big enough
33   }
34   {
35     MemoryMapping m(File(f.fd()), 0, sizeof(double));
36     const double volatile* d = m.asRange<double>().data();
37     EXPECT_EQ(*d, 37 * M_PI);
38   }
39 }
40
41 TEST(MemoryMapping, Move) {
42   File f = File::temporary();
43   {
44     WritableMemoryMapping m(File(f.fd()), 0, sizeof(double) * 2);
45     double volatile* d = m.asWritableRange<double>().data();
46     d[0] = 37 * M_PI;
47     WritableMemoryMapping m2(std::move(m));
48     double volatile* d2 = m2.asWritableRange<double>().data();
49     d2[1] = 39 * M_PI;
50   }
51   {
52     MemoryMapping m(File(f.fd()), 0, sizeof(double));
53     const double volatile* d = m.asRange<double>().data();
54     EXPECT_EQ(d[0], 37 * M_PI);
55     MemoryMapping m2(std::move(m));
56     const double volatile* d2 = m2.asRange<double>().data();
57     EXPECT_EQ(d2[1], 39 * M_PI);
58   }
59 }
60
61 TEST(MemoryMapping, DoublyMapped) {
62   File f = File::temporary();
63   // two mappings of the same memory, different addresses.
64   WritableMemoryMapping mw(File(f.fd()), 0, sizeof(double));
65   MemoryMapping mr(File(f.fd()), 0, sizeof(double));
66
67   double volatile* dw = mw.asWritableRange<double>().data();
68   const double volatile* dr = mr.asRange<double>().data();
69
70   // Show that it's truly the same value, even though the pointers differ
71   EXPECT_NE(dw, dr);
72   *dw = 42 * M_PI;
73   EXPECT_EQ(*dr, 42 * M_PI);
74   *dw = 43 * M_PI;
75   EXPECT_EQ(*dr, 43 * M_PI);
76 }
77
78 namespace {
79
80 void writeStringToFileOrDie(const std::string& str, int fd) {
81   const char* b = str.c_str();
82   size_t count = str.size();
83   ssize_t total_bytes = 0;
84   ssize_t r;
85   do {
86     r = write(fd, b, count);
87     if (r == -1) {
88       if (errno == EINTR) {
89         continue;
90       }
91       PCHECK(r) << "write";
92     }
93
94     total_bytes += r;
95     b += r;
96     count -= r;
97   } while (r != 0 && count);
98 }
99
100 }  // anonymous namespace
101
102 TEST(MemoryMapping, Simple) {
103   File f = File::temporary();
104   writeStringToFileOrDie("hello", f.fd());
105
106   {
107     MemoryMapping m(File(f.fd()));
108     EXPECT_EQ("hello", m.data());
109   }
110   {
111     MemoryMapping m(File(f.fd()), 1, 2);
112     EXPECT_EQ("el", m.data());
113   }
114 }
115
116 TEST(MemoryMapping, LargeFile) {
117   std::string fileData;
118   size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
119   fileData.reserve(fileSize);
120   for (size_t i = 0; i < fileSize; i++) {
121     fileData.push_back(0xff & random());
122   }
123
124   File f = File::temporary();
125   writeStringToFileOrDie(fileData, f.fd());
126
127   {
128     MemoryMapping m(File(f.fd()));
129     EXPECT_EQ(fileData, m.data());
130   }
131   {
132     size_t size = sysconf(_SC_PAGESIZE) * 2;
133     StringPiece s(fileData.data() + 9, size - 9);
134     MemoryMapping m(File(f.fd()), 9, size - 9);
135     EXPECT_EQ(s.toString(), m.data());
136   }
137 }
138
139 TEST(MemoryMapping, ZeroLength) {
140   File f = File::temporary();
141   MemoryMapping m(File(f.fd()));
142   EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
143   EXPECT_TRUE(m.mlocked());
144   EXPECT_EQ(0, m.data().size());
145 }
146
147 } // namespace folly