Coverage Report

Created: 2026-03-13 19:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
contrib/faiss/faiss/impl/mapped_io.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#include <stdio.h>
9
#include <string.h>
10
11
#ifdef __linux__
12
13
#include <fcntl.h>
14
#include <sys/mman.h>
15
#include <sys/stat.h>
16
#include <sys/types.h>
17
#include <unistd.h>
18
19
#elif defined(_WIN32)
20
21
#include <Windows.h> // @manual
22
#include <io.h>      // @manual
23
24
#endif
25
26
#include <cstring>
27
28
#include <faiss/impl/FaissAssert.h>
29
#include <faiss/impl/mapped_io.h>
30
31
namespace faiss {
32
33
#ifdef __linux__
34
35
struct MmappedFileMappingOwner::PImpl {
36
    void* ptr = nullptr;
37
    size_t ptr_size = 0;
38
39
0
    PImpl(const std::string& filename) {
40
0
        auto f = std::unique_ptr<FILE, decltype(&fclose)>(
41
0
                fopen(filename.c_str(), "r"), &fclose);
42
0
        FAISS_THROW_IF_NOT_FMT(
43
0
                f.get(),
44
0
                "could not open %s for reading: %s",
45
0
                filename.c_str(),
46
0
                strerror(errno));
47
48
        // get the size
49
0
        struct stat s;
50
0
        int status = fstat(fileno(f.get()), &s);
51
0
        FAISS_THROW_IF_NOT_FMT(
52
0
                status >= 0, "fstat() failed: %s", strerror(errno));
53
54
0
        const size_t filesize = s.st_size;
55
56
0
        void* address = mmap(
57
0
                nullptr, filesize, PROT_READ, MAP_SHARED, fileno(f.get()), 0);
58
0
        FAISS_THROW_IF_NOT_FMT(
59
0
                address != nullptr, "could not mmap(): %s", strerror(errno));
60
61
        // btw, fd can be closed here
62
63
0
        madvise(address, filesize, MADV_RANDOM);
64
65
        // save it
66
0
        ptr = address;
67
0
        ptr_size = filesize;
68
0
    }
69
70
0
    PImpl(FILE* f) {
71
        // get the size
72
0
        struct stat s;
73
0
        int status = fstat(fileno(f), &s);
74
0
        FAISS_THROW_IF_NOT_FMT(
75
0
                status >= 0, "fstat() failed: %s", strerror(errno));
76
77
0
        const size_t filesize = s.st_size;
78
79
0
        void* address =
80
0
                mmap(nullptr, filesize, PROT_READ, MAP_SHARED, fileno(f), 0);
81
0
        FAISS_THROW_IF_NOT_FMT(
82
0
                address != nullptr, "could not mmap(): %s", strerror(errno));
83
84
        // btw, fd can be closed here
85
86
0
        madvise(address, filesize, MADV_RANDOM);
87
88
        // save it
89
0
        ptr = address;
90
0
        ptr_size = filesize;
91
0
    }
92
93
0
    ~PImpl() {
94
        // todo: check for an error
95
0
        munmap(ptr, ptr_size);
96
0
    }
97
};
98
99
#elif defined(_WIN32)
100
101
struct MmappedFileMappingOwner::PImpl {
102
    void* ptr = nullptr;
103
    size_t ptr_size = 0;
104
    HANDLE mapping_handle = INVALID_HANDLE_VALUE;
105
106
    PImpl(const std::string& filename) {
107
        HANDLE file_handle = CreateFile(
108
                filename.c_str(),
109
                GENERIC_READ,
110
                FILE_SHARE_READ,
111
                nullptr,
112
                OPEN_EXISTING,
113
                0,
114
                nullptr);
115
        if (file_handle == INVALID_HANDLE_VALUE) {
116
            const auto error = GetLastError();
117
            FAISS_THROW_FMT(
118
                    "could not open the file, %s (error %d)",
119
                    filename.c_str(),
120
                    error);
121
        }
122
123
        // get the size of the file
124
        LARGE_INTEGER len_li;
125
        if (GetFileSizeEx(file_handle, &len_li) == 0) {
126
            const auto error = GetLastError();
127
128
            CloseHandle(file_handle);
129
130
            FAISS_THROW_FMT(
131
                    "could not get the file size, %s (error %d)",
132
                    filename.c_str(),
133
                    error);
134
        }
135
136
        // create a mapping
137
        mapping_handle = CreateFileMapping(
138
                file_handle, nullptr, PAGE_READONLY, 0, 0, nullptr);
139
        if (mapping_handle == 0) {
140
            const auto error = GetLastError();
141
142
            CloseHandle(file_handle);
143
144
            FAISS_THROW_FMT(
145
                    "could not create a file mapping, %s (error %d)",
146
                    filename.c_str(),
147
                    error);
148
        }
149
        CloseHandle(file_handle);
150
151
        char* data =
152
                (char*)MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0);
153
        if (data == nullptr) {
154
            const auto error = GetLastError();
155
156
            CloseHandle(mapping_handle);
157
            mapping_handle = INVALID_HANDLE_VALUE;
158
159
            FAISS_THROW_FMT(
160
                    "could not get map the file, %s (error %d)",
161
                    filename.c_str(),
162
                    error);
163
        }
164
165
        ptr = data;
166
        ptr_size = len_li.QuadPart;
167
    }
168
169
    PImpl(FILE* f) {
170
        // obtain a HANDLE from a FILE
171
        const int fd = _fileno(f);
172
        if (fd == -1) {
173
            // no good
174
            FAISS_THROW_FMT("could not get a HANDLE");
175
        }
176
177
        HANDLE file_handle = (HANDLE)_get_osfhandle(fd);
178
        if (file_handle == INVALID_HANDLE_VALUE) {
179
            FAISS_THROW_FMT("could not get an OS HANDLE");
180
        }
181
182
        // get the size of the file
183
        LARGE_INTEGER len_li;
184
        if (GetFileSizeEx(file_handle, &len_li) == 0) {
185
            const auto error = GetLastError();
186
            FAISS_THROW_FMT("could not get the file size (error %d)", error);
187
        }
188
189
        // create a mapping
190
        mapping_handle = CreateFileMapping(
191
                file_handle, nullptr, PAGE_READONLY, 0, 0, nullptr);
192
        if (mapping_handle == 0) {
193
            const auto error = GetLastError();
194
            FAISS_THROW_FMT(
195
                    "could not create a file mapping, (error %d)", error);
196
        }
197
198
        // the handle is provided externally, so this is not our business
199
        //   to close file_handle.
200
201
        char* data =
202
                (char*)MapViewOfFile(mapping_handle, FILE_MAP_READ, 0, 0, 0);
203
        if (data == nullptr) {
204
            const auto error = GetLastError();
205
206
            CloseHandle(mapping_handle);
207
            mapping_handle = INVALID_HANDLE_VALUE;
208
209
            FAISS_THROW_FMT("could not get map the file, (error %d)", error);
210
        }
211
212
        ptr = data;
213
        ptr_size = len_li.QuadPart;
214
    }
215
216
    ~PImpl() {
217
        if (mapping_handle != INVALID_HANDLE_VALUE) {
218
            UnmapViewOfFile(ptr);
219
            CloseHandle(mapping_handle);
220
221
            mapping_handle = INVALID_HANDLE_VALUE;
222
            ptr = nullptr;
223
        }
224
    }
225
};
226
227
#else
228
229
struct MmappedFileMappingOwner::PImpl {
230
    void* ptr = nullptr;
231
    size_t ptr_size = 0;
232
233
    PImpl(const std::string& filename) {
234
        FAISS_THROW_MSG("Not implemented");
235
    }
236
237
    PImpl(FILE* f) {
238
        FAISS_THROW_MSG("Not implemented");
239
    }
240
};
241
242
#endif
243
244
0
MmappedFileMappingOwner::MmappedFileMappingOwner(const std::string& filename) {
245
0
    p_impl = std::make_unique<MmappedFileMappingOwner::PImpl>(filename);
246
0
}
247
248
0
MmappedFileMappingOwner::MmappedFileMappingOwner(FILE* f) {
249
0
    p_impl = std::make_unique<MmappedFileMappingOwner::PImpl>(f);
250
0
}
251
252
0
MmappedFileMappingOwner::~MmappedFileMappingOwner() = default;
253
254
//
255
0
void* MmappedFileMappingOwner::data() const {
256
0
    return p_impl->ptr;
257
0
}
258
259
0
size_t MmappedFileMappingOwner::size() const {
260
0
    return p_impl->ptr_size;
261
0
}
262
263
MappedFileIOReader::MappedFileIOReader(
264
        const std::shared_ptr<MmappedFileMappingOwner>& owner)
265
0
        : mmap_owner(owner) {}
266
267
// this operation performs a copy
268
0
size_t MappedFileIOReader::operator()(void* ptr, size_t size, size_t nitems) {
269
0
    if (size * nitems == 0) {
270
0
        return 0;
271
0
    }
272
273
0
    char* ptr_c = nullptr;
274
275
0
    const size_t actual_nitems = this->mmap((void**)&ptr_c, size, nitems);
276
0
    if (actual_nitems > 0) {
277
0
        memcpy(ptr, ptr_c, size * actual_nitems);
278
0
    }
279
280
0
    return actual_nitems;
281
0
}
282
283
// this operation returns a mmapped address, owned by mmap_owner
284
0
size_t MappedFileIOReader::mmap(void** ptr, size_t size, size_t nitems) {
285
0
    if (size == 0) {
286
0
        return nitems;
287
0
    }
288
289
0
    size_t actual_size = size * nitems;
290
0
    if (pos + size * nitems > mmap_owner->size()) {
291
0
        actual_size = mmap_owner->size() - pos;
292
0
    }
293
294
0
    size_t actual_nitems = (actual_size + size - 1) / size;
295
0
    if (actual_nitems == 0) {
296
0
        return 0;
297
0
    }
298
299
    // get an address
300
0
    *ptr = (void*)(reinterpret_cast<const char*>(mmap_owner->data()) + pos);
301
302
    // alter pos
303
0
    pos += size * actual_nitems;
304
305
0
    return actual_nitems;
306
0
}
307
308
0
int MappedFileIOReader::filedescriptor() {
309
    // todo
310
0
    return -1;
311
0
}
312
313
} // namespace faiss