#include <FileDevice.h>
Inheritance diagram for FileDevice:
Public Member Functions | |
FileDevice (std::string filename, DeviceMode mode, FileSize initialSize) | |
Opens a file device. | |
virtual | ~FileDevice () |
void | transfer (RandomAccessRequest const &request) |
Executes a synchronous transfer request for a single random access binding. | |
void | flush () |
void | close () |
bool | isOpen () const |
| |
FileSize | getSizeInBytes () |
void | setSizeInBytes (FileSize cbNew) |
Protected Attributes | |
FileSize | cbFile |
current file size in bytes | |
int | handle |
the opened OS file | |
DeviceMode | mode |
mode in which file was opened | |
std::string | filename |
path to file in file system | |
StrictMutex | mutex |
On Cygwin, there's no pread/pwrite, so all I/O has to be synchronized per device. |
Definition at line 38 of file FileDevice.h.
FileDevice::FileDevice | ( | std::string | filename, | |
DeviceMode | mode, | |||
FileSize | initialSize | |||
) |
Opens a file device.
filename | path to file | |
mode | modifiers for how to open file | |
initialSize | the initial size (in bytes) of the device, if creating a new file |
Definition at line 44 of file FileDevice.cpp.
References cbFile, DeviceMode::create, DeviceMode::direct, filename, handle, isOpen(), mode, DeviceMode::readOnly, DeviceMode::sequential, setSizeInBytes(), and DeviceMode::temporary.
00046 { 00047 filename = filenameInit; 00048 mode = openMode; 00049 00050 #ifdef __MSVC__ 00051 00052 DWORD fdwCreate = mode.create ? CREATE_ALWAYS : OPEN_EXISTING; 00053 00054 DWORD fdwFlags = FILE_FLAG_OVERLAPPED; 00055 00056 DWORD fdwAccess = GENERIC_READ; 00057 if (!mode.readOnly) { 00058 fdwAccess |= GENERIC_WRITE; 00059 } 00060 if (mode.direct) { 00061 fdwFlags |= FILE_FLAG_NO_BUFFERING; 00062 } 00063 if (mode.sequential) { 00064 fdwFlags |= FILE_FLAG_SEQUENTIAL_SCAN; 00065 } else { 00066 fdwFlags |= FILE_FLAG_RANDOM_ACCESS; 00067 } 00068 if (mode.temporary) { 00069 fdwFlags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; 00070 } else { 00071 fdwFlags |= FILE_ATTRIBUTE_NORMAL; 00072 } 00073 00074 // REVIEW: I used FILE_SHARE_ so that recovery tests could reopen a 00075 // log file for read while it was still open for write by the original 00076 // txn. Should probably fix the tests instead, in case allowing sharing 00077 // could hinder performance. 00078 00079 handle = reinterpret_cast<int>( 00080 CreateFile( 00081 filename.c_str(), 00082 fdwAccess, 00083 FILE_SHARE_READ | FILE_SHARE_WRITE, 00084 NULL, 00085 fdwCreate, 00086 fdwFlags, 00087 NULL)); 00088 00089 if (!isOpen()) { 00090 std::ostringstream oss; 00091 oss << "Failed to open file " << filename; 00092 throw SysCallExcn(oss.str()); 00093 } 00094 00095 DWORD cbHigh = 0; 00096 DWORD cbLow = GetFileSize(HANDLE(handle),&cbHigh); 00097 if (cbLow == INVALID_FILE_SIZE) { 00098 std::ostringstream oss; 00099 oss << "Failed to get size for file " << filename; 00100 throw SysCallExcn(oss.str()); 00101 } 00102 LARGE_INTEGER cbLarge; 00103 cbLarge.LowPart = cbLow; 00104 cbLarge.HighPart = cbHigh; 00105 cbFile = cbLarge.QuadPart; 00106 if (mode.create && initialSize > 0) { 00107 setSizeInBytes(initialSize); 00108 } 00109 00110 #else 00111 00112 int access = O_LARGEFILE; 00113 int permission = S_IRUSR; 00114 if (mode.readOnly) { 00115 access |= O_RDONLY; 00116 } else { 00117 access |= O_RDWR; 00118 permission |= S_IWUSR; 00119 } 00120 if (mode.create) { 00121 access |= O_CREAT | O_TRUNC; 00122 } 00123 00124 if (mode.direct) { 00125 // REVIEW jvs 4-Dec-2008: Comment below used to be true, but probably 00126 // only on 2.4 kernels. 2.6 kernels seem to be happy with 00127 // O_DIRECT+pwrite. 00128 // (http://lkml.indiana.edu/hypermail/linux/kernel/0511.2/1758.html). 00129 // So we can probably clean this up now. 00130 access |= O_SYNC; 00131 // NOTE: We don't actually set O_DIRECT here, because on Linux 00132 // that results in EINVAL errors from pwrite. Instead, 00133 // O_DIRECT is set from AioLinuxScheduler, because it is required 00134 // for libaio. 00135 } 00136 00137 handle = ::open(filename.c_str(), access, permission); 00138 if (!isOpen()) { 00139 std::ostringstream oss; 00140 oss << "Failed to open file " << filename; 00141 throw SysCallExcn(oss.str()); 00142 } 00143 if (flock(handle, LOCK_SH | LOCK_NB) < 0) { 00144 throw SysCallExcn("File lock failed"); 00145 } 00146 cbFile = ::lseek(handle,0,SEEK_END); 00147 00148 // Preallocate the file if we're creating the file, and an initial size 00149 // is specified. 00150 if (mode.create && initialSize > 0) { 00151 int rc = posix_fallocate(handle, 0, initialSize); 00152 if (rc) { 00153 throw SysCallExcn("File allocation failed", rc); 00154 } 00155 cbFile = initialSize; 00156 } 00157 00158 #endif 00159 }
FileDevice::~FileDevice | ( | ) | [virtual] |
void FileDevice::transfer | ( | RandomAccessRequest const & | request | ) |
Executes a synchronous transfer request for a single random access binding.
This is an all-or-nothing request, so unless the result size is equal to the requested transfer size, the request is considered a failure. However, no exception is thrown when failure occurs; instead, the binding notification method is called.
request | transfer specification; must have exactly one binding |
Reimplemented in RandomAccessFileDevice.
Definition at line 217 of file FileDevice.cpp.
References RandomAccessRequest::bindingList, RandomAccessRequest::cbOffset, RandomAccessRequest::cbTransfer, handle, RandomAccessRequest::READ, and RandomAccessRequest::type.
Referenced by RandomAccessFileDevice::transfer().
00218 { 00219 FileSize cbActual; 00220 assert(request.bindingList.size() == 1); 00221 #ifdef __MSVC__ 00222 LARGE_INTEGER largeInt; 00223 RandomAccessRequestBinding &binding = request.bindingList.front(); 00224 largeInt.QuadPart = request.cbOffset; 00225 binding.Offset = largeInt.LowPart; 00226 binding.OffsetHigh = largeInt.HighPart; 00227 00228 DWORD dwActual = 0; 00229 BOOL bCompleted; 00230 if (request.type == RandomAccessRequest::READ) { 00231 bCompleted = ReadFile( 00232 HANDLE(handle), 00233 request.bindingList.front().getBuffer(), 00234 request.cbTransfer, 00235 &dwActual, 00236 &binding); 00237 } else { 00238 bCompleted = WriteFile( 00239 HANDLE(handle), 00240 request.bindingList.front().getBuffer(), 00241 request.cbTransfer, 00242 &dwActual, 00243 &binding); 00244 } 00245 if (!bCompleted) { 00246 if (GetLastError() == ERROR_IO_PENDING) { 00247 if (!GetOverlappedResult( 00248 HANDLE(handle), 00249 &binding, 00250 &dwActual, 00251 TRUE)) 00252 { 00253 dwActual = 0; 00254 } 00255 } else { 00256 dwActual = 0; 00257 } 00258 } 00259 cbActual = dwActual; 00260 #else 00261 if (request.type == RandomAccessRequest::READ) { 00262 cbActual = ::pread( 00263 handle, 00264 request.bindingList.front().getBuffer(), 00265 request.cbTransfer, 00266 request.cbOffset); 00267 } else { 00268 cbActual = ::pwrite( 00269 handle, 00270 request.bindingList.front().getBuffer(), 00271 request.cbTransfer, 00272 request.cbOffset); 00273 } 00274 #endif 00275 request.bindingList.front().notifyTransferCompletion( 00276 cbActual == request.cbTransfer); 00277 }
void FileDevice::flush | ( | ) |
Reimplemented in RandomAccessFileDevice.
Definition at line 182 of file FileDevice.cpp.
References handle, mode, and DeviceMode::readOnly.
Referenced by RandomAccessFileDevice::flush().
00183 { 00184 if (mode.readOnly) { 00185 return; 00186 } 00187 #ifdef __MSVC__ 00188 if (!FlushFileBuffers(HANDLE(handle))) { 00189 throw SysCallExcn("Flush failed"); 00190 } 00191 #else 00192 if (::fdatasync(handle)) { 00193 throw SysCallExcn("Flush failed"); 00194 } 00195 #endif 00196 }
void FileDevice::close | ( | ) |
Definition at line 168 of file FileDevice.cpp.
References filename, handle, isOpen(), mode, and DeviceMode::temporary.
Referenced by ~FileDevice().
00169 { 00170 assert(isOpen()); 00171 #ifdef __MSVC__ 00172 CloseHandle(HANDLE(handle)); 00173 #else 00174 ::close(handle); 00175 if (mode.temporary) { 00176 ::unlink(filename.c_str()); 00177 } 00178 #endif 00179 handle = -1; 00180 }
bool FileDevice::isOpen | ( | ) | const [inline] |
Definition at line 100 of file FileDevice.h.
Referenced by close(), FileDevice(), and ~FileDevice().
00101 { 00102 return handle == -1 ? 0 : 1; 00103 }
FileSize FileDevice::getSizeInBytes | ( | ) | [inline] |
Reimplemented in RandomAccessFileDevice.
Definition at line 105 of file FileDevice.h.
Referenced by RandomAccessFileDevice::getSizeInBytes().
00106 { 00107 return cbFile; 00108 }
void FileDevice::setSizeInBytes | ( | FileSize | cbNew | ) |
Reimplemented in RandomAccessFileDevice.
Definition at line 198 of file FileDevice.cpp.
References cbFile, and handle.
Referenced by FileDevice(), and RandomAccessFileDevice::setSizeInBytes().
00199 { 00200 #ifdef __MSVC__ 00201 LARGE_INTEGER cbLarge; 00202 cbLarge.QuadPart = cbFileNew; 00203 if (!SetFilePointerEx(HANDLE(handle),cbLarge,NULL,FILE_BEGIN)) { 00204 throw SysCallExcn("Resize file failed: SetFilePointer"); 00205 } 00206 if (!SetEndOfFile(HANDLE(handle))) { 00207 throw SysCallExcn("Resize file failed: SetEndOfFile"); 00208 } 00209 #else 00210 if (::ftruncate(handle,cbFileNew)) { 00211 throw SysCallExcn("Resize file failed"); 00212 } 00213 #endif 00214 cbFile = cbFileNew; 00215 }
FileSize FileDevice::cbFile [protected] |
current file size in bytes
Definition at line 45 of file FileDevice.h.
Referenced by FileDevice(), and setSizeInBytes().
int FileDevice::handle [protected] |
the opened OS file
Definition at line 50 of file FileDevice.h.
Referenced by close(), FileDevice(), flush(), RandomAccessFileDevice::getHandle(), RandomAccessFileDevice::prepareTransfer(), setSizeInBytes(), and transfer().
DeviceMode FileDevice::mode [protected] |
mode in which file was opened
Definition at line 55 of file FileDevice.h.
Referenced by close(), FileDevice(), and flush().
std::string FileDevice::filename [protected] |
path to file in file system
Definition at line 60 of file FileDevice.h.
Referenced by close(), and FileDevice().
StrictMutex FileDevice::mutex [protected] |
On Cygwin, there's no pread/pwrite, so all I/O has to be synchronized per device.
Definition at line 66 of file FileDevice.h.