FileDevice Class Reference

FileDevice is a base class for devices built atop the OS file system. More...

#include <FileDevice.h>

Inheritance diagram for FileDevice:

RandomAccessFileDevice List of all members.

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
 
Returns:
whether the device file is currently open

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.

Detailed Description

FileDevice is a base class for devices built atop the OS file system.

Definition at line 38 of file FileDevice.h.


Constructor & Destructor Documentation

FileDevice::FileDevice ( std::string  filename,
DeviceMode  mode,
FileSize  initialSize 
)

Opens a file device.

Parameters:
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]

Definition at line 161 of file FileDevice.cpp.

References close(), and isOpen().

00162 {
00163     if (isOpen()) {
00164         close();
00165     }
00166 }


Member Function Documentation

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.

Parameters:
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]

Returns:
whether the device file is currently open

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 }


Member Data Documentation

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.


The documentation for this class was generated from the following files:
Generated on Mon Jun 22 04:00:32 2009 for Fennel by  doxygen 1.5.1