2 * Copyright (C) 2017 Cisco Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // @author Changxue Deng <chadeng@cisco.com>
27 #include "mmap_file.h"
30 #include "rollable_file.h"
34 MmapFileIO::MmapFileIO(const std::string &fpath, int mode, off_t filesize, bool sync)
35 : FileIO(fpath, mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, sync)
39 mmap_start = 0xFFFFFFFFFFFFFFFF;
46 if(options & MMAP_ANONYMOUS_MODE)
48 // Do not open file in anonymous mode.
52 Logger::Log(LOG_LEVEL_DEBUG, "opening file " + fpath);
57 int level = LOG_LEVEL_DEBUG;
59 level = LOG_LEVEL_ERROR;
60 Logger::Log(level, "failed to open file %s with mode %d, errno %d",
61 fpath.c_str(), mode, errno);
65 if(filesize > 0 && (mode & O_CREAT))
67 if(TruncateFile(filesize) != 0)
69 Logger::Log(LOG_LEVEL_ERROR, "failed to truncate file %s with size %d",
70 fpath.c_str(), static_cast<int>(filesize));
76 MmapFileIO::~MmapFileIO()
81 uint8_t* MmapFileIO::MapFile(size_t size, off_t offset, bool sliding)
87 if(options & MMAP_ANONYMOUS_MODE)
89 assert(offset == 0 && !sliding);
90 addr = static_cast<unsigned char *>(mmap(NULL, size, mode,
91 MAP_SHARED | MAP_ANONYMOUS, -1, 0));
95 addr = static_cast<unsigned char *>(FileIO::MapFile(size, mode,
99 if(addr == MAP_FAILED)
101 Logger::Log(LOG_LEVEL_WARN, "%s mmap (%s) failed errno=%d offset=%llu size=%llu",
102 (options & MMAP_ANONYMOUS_MODE) ? "anon":"",
103 path.c_str(), errno, offset, size);
112 mmap_end = offset + size;
115 if(mode & PROT_WRITE)
117 Logger::Log(LOG_LEVEL_DEBUG, "mmap file %s, sliding=%d, size=%d, offset=%d",
118 path.c_str(), sliding, size, offset);
124 void MmapFileIO::UnMapFile()
126 if(mmap_file && addr != NULL)
128 munmap(addr, mmap_size);
134 // find the current offset first
135 // call RandomWrite using the offset
136 // reset the offset based on the number of bytes written
137 size_t MmapFileIO::SeqWrite(const void *data, size_t size)
139 size_t bytes_written = MmapFileIO::RandomWrite(data, size, curr_offset);
140 curr_offset += bytes_written;
141 return bytes_written;
144 size_t MmapFileIO::RandomWrite(const void *data, size_t size, off_t offset)
149 size_t bytes_written;
153 // If the file is not mmaped, we just need to write to the file.
154 bytes_written = FileIO::RandomWrite(data, size, offset);
155 if(bytes_written + offset > max_offset)
157 max_offset = bytes_written + offset;
159 return bytes_written;
162 // If the file is mmaped, we need to write to the memory or file.
163 off_t offset_end = static_cast<off_t>(size) + offset;
164 const unsigned char *ptr = static_cast<const unsigned char *>(data);
165 if(offset < mmap_start)
167 if(offset_end <= mmap_start)
169 // no overlap with mmap region
170 bytes_written = FileIO::RandomWrite(ptr, size, offset);
172 else if(offset_end <= mmap_end)
174 // partial overlap with left region
175 size_t written_left = mmap_start - offset;
176 bytes_written = FileIO::RandomWrite(ptr, written_left, offset);
178 // partial overlap with mmap region
179 memcpy(addr+mmap_start, ptr, size-written_left);
180 bytes_written += size - written_left;
182 RollableFile::ShmSync(addr+mmap_start, size-written_left);
186 // partial overlap with left region
187 size_t written_left = mmap_start - offset;
188 bytes_written = FileIO::RandomWrite(ptr, written_left, offset);
190 // full overlap with mmap region
191 memcpy(addr+mmap_start, ptr, mmap_size);
192 bytes_written += mmap_size;
193 written_left += mmap_size;
196 RollableFile::ShmSync(addr+mmap_start, mmap_size);
197 // partial overlap with right region
198 bytes_written += FileIO::RandomWrite(ptr, size-written_left, mmap_end);
201 else if(offset < mmap_end)
203 if(offset_end <= mmap_end)
205 // full data is within the mmap region
206 memcpy(addr+offset, ptr, size);
207 bytes_written = size;
209 RollableFile::ShmSync(addr+offset, size);
213 // partial overlap with mmap region
214 size_t written_left = mmap_end - offset;
215 memcpy(addr+offset, ptr, written_left);
217 bytes_written = written_left;
219 RollableFile::ShmSync(addr+offset, written_left);
220 // partial overlap with the right region
221 bytes_written += FileIO::RandomWrite(ptr, size-written_left, mmap_end);
226 // no overlap with mmap region
227 bytes_written = FileIO::RandomWrite(ptr, size, offset);
230 if(bytes_written + offset > max_offset)
231 max_offset = bytes_written + offset;
233 return bytes_written;
237 // find the current offset first
238 // call RandomRead using the offset
239 // reset the offset based on the number of bytes read
240 size_t MmapFileIO::SeqRead(void *buff, size_t size)
242 size_t bytes_read = MmapFileIO::RandomRead(buff, size, curr_offset);
243 curr_offset += bytes_read;
247 size_t MmapFileIO::RandomRead(void *buff, size_t size, off_t offset)
254 // If file is not mmaped, go directly to file IO.
255 return FileIO::RandomRead(buff, size, offset);
259 off_t offset_end = static_cast<off_t>(size) + offset;
260 unsigned char *ptr = static_cast<unsigned char *>(buff);
261 if(offset < mmap_start)
263 if(offset_end <= mmap_start)
265 // no overlap with mmap region
266 bytes_read = FileIO::RandomRead(ptr, size, offset);
268 else if(offset_end <= mmap_end)
270 // partial overlap with left region
271 size_t read_left = mmap_start - offset;
272 bytes_read = FileIO::RandomRead(ptr, read_left, offset);
274 // partial overlap with mmap region
275 memcpy(ptr, addr+mmap_start, size-read_left);
276 bytes_read += size - read_left;
280 // partial overlap with left region
281 size_t read_left = mmap_start - offset;
282 bytes_read = FileIO::RandomRead(ptr, read_left, offset);
284 // full overlap with mmap region
285 memcpy(ptr, addr+mmap_start, mmap_size);
286 bytes_read += mmap_size;
287 read_left += mmap_size;
289 // partial overlap with right region
290 bytes_read += FileIO::RandomRead(ptr, size-read_left, mmap_end);
293 else if(offset < mmap_end)
295 if(offset_end <= mmap_end)
297 // full data is within the mmap region
298 memcpy(ptr, addr+offset, size);
303 // full overlap with mmap region
304 size_t read_left = mmap_end - offset;
305 memcpy(ptr, addr+offset, read_left);
307 bytes_read = read_left;
308 // partial overlap with the right region
309 bytes_read += FileIO::RandomRead(ptr, size-read_left, mmap_end);
314 // no overlap with mmap region
315 bytes_read = FileIO::RandomRead(ptr, size, offset);
321 bool MmapFileIO::IsMapped() const
326 uint8_t* MmapFileIO::GetMapAddr() const
331 void MmapFileIO::Flush()
333 if(options & MMAP_ANONYMOUS_MODE)
337 msync(addr, mmap_size, MS_SYNC);