1 /*
2 * Net2FileSystem.cpp
3 *
4 * This source file is part of the FoundationDB open source project
5 *
6 * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21
22 #include "fdbrpc/Net2FileSystem.h"
23
24 // Define boost::asio::io_service
25 #include <algorithm>
26 #define BOOST_SYSTEM_NO_LIB
27 #define BOOST_DATE_TIME_NO_LIB
28 #define BOOST_REGEX_NO_LIB
29 #include <boost/asio.hpp>
30 #include <boost/bind.hpp>
31
32 #define FILESYSTEM_IMPL 1
33
34 #include "fdbrpc/AsyncFileCached.actor.h"
35 #include "fdbrpc/AsyncFileEIO.actor.h"
36 #include "fdbrpc/AsyncFileWinASIO.actor.h"
37 #include "fdbrpc/AsyncFileKAIO.actor.h"
38 #include "flow/AsioReactor.h"
39 #include "flow/Platform.h"
40 #include "fdbrpc/AsyncFileWriteChecker.h"
41
42 // Opens a file for asynchronous I/O
open(std::string filename,int64_t flags,int64_t mode)43 Future< Reference<class IAsyncFile> > Net2FileSystem::open( std::string filename, int64_t flags, int64_t mode )
44 {
45 #ifdef __linux__
46 if (checkFileSystem) {
47 dev_t fileDeviceId = getDeviceId(filename);
48 if (fileDeviceId != this->fileSystemDeviceId) {
49 TraceEvent(SevError, "DeviceIdMismatched").detail("FileSystemDeviceId", this->fileSystemDeviceId).detail("FileDeviceId", fileDeviceId);
50 throw io_error();
51 }
52 }
53 #endif
54
55 if ( (flags & IAsyncFile::OPEN_EXCLUSIVE) ) ASSERT( flags & IAsyncFile::OPEN_CREATE );
56 if (!(flags & IAsyncFile::OPEN_UNCACHED))
57 return AsyncFileCached::open(filename, flags, mode);
58
59 Future<Reference<IAsyncFile>> f;
60 #ifdef __linux__
61 // In the vast majority of cases, we wish to use Kernel AIO. However, some systems
62 // dont properly support don’t properly support kernel async I/O without O_DIRECT
63 // or AIO at all. In such cases, DISABLE_POSIX_KERNEL_AIO knob can be enabled to fallback to
64 // EIO instead of Kernel AIO.
65 if ((flags & IAsyncFile::OPEN_UNBUFFERED) && !(flags & IAsyncFile::OPEN_NO_AIO) &&
66 !FLOW_KNOBS->DISABLE_POSIX_KERNEL_AIO)
67 f = AsyncFileKAIO::open(filename, flags, mode, NULL);
68 else
69 #endif
70 f = Net2AsyncFile::open(filename, flags, mode, static_cast<boost::asio::io_service*> ((void*) g_network->global(INetwork::enASIOService)));
71 if(FLOW_KNOBS->PAGE_WRITE_CHECKSUM_HISTORY > 0)
72 f = map(f, [=](Reference<IAsyncFile> r) { return Reference<IAsyncFile>(new AsyncFileWriteChecker(r)); });
73 return f;
74 }
75
76 // Deletes the given file. If mustBeDurable, returns only when the file is guaranteed to be deleted even after a power failure.
deleteFile(std::string filename,bool mustBeDurable)77 Future< Void > Net2FileSystem::deleteFile( std::string filename, bool mustBeDurable )
78 {
79 return Net2AsyncFile::deleteFile(filename, mustBeDurable);
80 }
81
lastWriteTime(std::string filename)82 Future< std::time_t > Net2FileSystem::lastWriteTime( std::string filename ) {
83 return Net2AsyncFile::lastWriteTime( filename );
84 }
85
newFileSystem(double ioTimeout,std::string fileSystemPath)86 void Net2FileSystem::newFileSystem(double ioTimeout, std::string fileSystemPath)
87 {
88 g_network->setGlobal(INetwork::enFileSystem, (flowGlobalType) new Net2FileSystem(ioTimeout, fileSystemPath));
89 }
90
Net2FileSystem(double ioTimeout,std::string fileSystemPath)91 Net2FileSystem::Net2FileSystem(double ioTimeout, std::string fileSystemPath)
92 {
93 Net2AsyncFile::init();
94 #ifdef __linux__
95 AsyncFileKAIO::init( Reference<IEventFD>(N2::ASIOReactor::getEventFD()), ioTimeout );
96
97 if (fileSystemPath.empty()) {
98 checkFileSystem = false;
99 } else {
100 checkFileSystem = true;
101
102 try {
103 this->fileSystemDeviceId = getDeviceId(fileSystemPath);
104 if (fileSystemPath != "/") {
105 dev_t fileSystemParentDeviceId = getDeviceId(parentDirectory(fileSystemPath));
106 if (this->fileSystemDeviceId == fileSystemParentDeviceId) {
107 criticalError(FDB_EXIT_ERROR, "FileSystemError", format("`%s' is not a mount point", fileSystemPath.c_str()).c_str());
108 }
109 }
110 } catch (Error& e) {
111 criticalError(FDB_EXIT_ERROR, "FileSystemError", format("Could not get device id from `%s'", fileSystemPath.c_str()).c_str());
112 }
113 }
114 #endif
115 }
116