aboutsummaryrefslogtreecommitdiff
path: root/src/lib/mapped-file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mapped-file.cc')
-rw-r--r--src/lib/mapped-file.cc105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/lib/mapped-file.cc b/src/lib/mapped-file.cc
new file mode 100644
index 0000000..2868cdb
--- /dev/null
+++ b/src/lib/mapped-file.cc
@@ -0,0 +1,105 @@
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Copyright 2005-2010 Google, Inc.
+// Author: sorenj@google.com (Jeffrey Sorensen)
+
+#include <fst/mapped-file.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+namespace fst {
+
+// Alignment required for mapping structures (in bytes.) Regions of memory
+// that are not aligned upon a 128 bit boundary will be read from the file
+// instead. This is consistent with the alignment boundary set in the
+// const and compact fst code.
+const int MappedFile::kArchAlignment = 16;
+
+MappedFile::MappedFile(const MemoryRegion &region) : region_(region) { }
+
+MappedFile::~MappedFile() {
+ if (region_.size != 0) {
+ if (region_.mmap != NULL) {
+ VLOG(1) << "munmap'ed " << region_.size << " bytes at " << region_.mmap;
+ if (munmap(region_.mmap, region_.size) != 0) {
+ LOG(ERROR) << "failed to unmap region: "<< strerror(errno);
+ }
+ } else {
+ operator delete(region_.data);
+ }
+ }
+}
+
+MappedFile* MappedFile::Allocate(size_t size) {
+ MemoryRegion region;
+ region.data = size == 0 ? NULL : operator new(size);
+ region.mmap = NULL;
+ region.size = size;
+ return new MappedFile(region);
+}
+
+MappedFile* MappedFile::Borrow(void *data) {
+ MemoryRegion region;
+ region.data = data;
+ region.mmap = data;
+ region.size = 0;
+ return new MappedFile(region);
+}
+
+MappedFile* MappedFile::Map(istream* s, const FstReadOptions &opts,
+ size_t size) {
+ std::streampos spos = s->tellg();
+ if (opts.mode == FstReadOptions::MAP && spos >= 0 &&
+ spos % kArchAlignment == 0) {
+ size_t pos = spos;
+ int fd = open(opts.source.c_str(), O_RDONLY);
+ if (fd != -1) {
+ int pagesize = getpagesize();
+ off_t offset = pos % pagesize;
+ off_t upsize = size + offset;
+ void *map = mmap(0, upsize, PROT_READ, MAP_SHARED, fd, pos - offset);
+ char *data = reinterpret_cast<char*>(map);
+ if (close(fd) == 0 && map != MAP_FAILED) {
+ MemoryRegion region;
+ region.mmap = map;
+ region.size = upsize;
+ region.data = reinterpret_cast<void*>(data + offset);
+ MappedFile *mmf = new MappedFile(region);
+ s->seekg(pos + size, ios::beg);
+ if (s) {
+ VLOG(1) << "mmap'ed region of " << size << " at offset " << pos
+ << " from " << opts.source.c_str() << " to addr " << map;
+ return mmf;
+ }
+ delete mmf;
+ } else {
+ LOG(INFO) << "Mapping of file failed: " << strerror(errno);
+ }
+ }
+ }
+ // If all else fails resort to reading from file into allocated buffer.
+ if (opts.mode != FstReadOptions::READ) {
+ LOG(WARNING) << "File mapping at offset " << spos << " of file "
+ << opts.source << " could not be honored, reading instead.";
+ }
+ MappedFile* mf = Allocate(size);
+ if (!s->read(reinterpret_cast<char*>(mf->mutable_data()), size)) {
+ delete mf;
+ return NULL;
+ }
+ return mf;
+}
+
+} // namespace fst