Detailed Description
File handle pool and simple file operations e.g.
FileOffset offset types:
copy and delete.
Introduction
Implements a pool of file handles for use within multi-threaded environments where the overhead of opening and closing a file handle for each thread would be too great. Primarily used to load collection items from file with file based collections or where a cache is used.
Creation
The fiftyoneDegreesFilePoolInit method is used to initialise a pointer to a fiftyoneDegreesFilePool. A concurrency value is provided to indicate the maximum number of threads that will be in operation. If this value is lower than the actual number of threads the stack can be exhausted and a null pointer is returned instead of a valid file handle. The concurrency value must always be the same or greater than the number of threads. When compiled in single threaded operation a pool is not strictly required and the implementation maintains a simple stack for consistency of interface and to minimise divergent code.
Get & Release
Handles are retrieved from the pool via the fiftyoneDegreesFileHandleGet method. The handle MUST be returned with the fiftyoneDegreesFileHandleRelease method when it is finished with. The handle will always be open and ready for read only operation. The position of the handle within the source file cannot be assumed. If too many threads are accessing the pool simultaneously, meaning a handle cannot be secured, then a NULL pointer is returned.
Free
The handles are closed when the reader is released via the fiftyoneDegreesFilePoolRelease method. Any memory allocated by the implementation for the stack is freed.
File Operations
Common file operations can also be carried out using the methods defined here. The supported operations are:
copy : fiftyoneDegreesFileCopy
create directory : fiftyoneDegreesFileCreateDirectory
create temp file : fiftyoneDegreesFileCreateTempFile
delete : fiftyoneDegreesFileDelete
get existing temp file : fiftyoneDegreesFileGetExistingTempFile
get file name : fiftyoneDegreesFileGetFileName
get path : fiftyoneDegreesFileGetPath
get size : fiftyoneDegreesFileGetSize
open : fiftyoneDegreesFileOpen
read to byte array : fiftyoneDegreesFileReadToByteArray
write : fiftyoneDegreesFileWrite
Usage Example
const char *fileName;
&filePool,
fileName,
1,
exception);
&pool,
exception);
}
}
Design
To improve performance in multi-threaded operation a non locking stack is used where a Compare and Swap (CAS) atomic operation is used to pop and push handles on and off the stack. The design was adapted from the following article (http://nullprogram.com/blog/2014/09/02/) which explains some of the challenges involved including the ABA problem (https://en.wikipedia.org/wiki/ABA_problem). It is for this reason the head structure is implemented as a union between the values and the exchange integer. Pointers are not used as the address space for the stack is continuous and always very small compared to the total addressable memory space.
- signed
FileOffset – for interop with native API (fseek/ftell)
- unsigned
FileOffsetUnsigned – as present in data file
if FIFTYONE_DEGREES_LARGE_DATA_FILE_SUPPORT macro is defined, both types will be 64-bit.
Motivation for this is that an offset in a large file beyond 4GB is not addressable by a uint32_t variable.
For files smaller than 4GB uint32_t is fully sufficient to address an offset.
fseek/ftell functions MAY also fail on files larger than 2 GiB due to the limitations of long int type used, so enabling the option MIGHT be necessary in those cases as well.
On POSIX systems _FILE_OFFSET_BITS should be defined as 64 at the same time for off_t (used by fseeko/ftello from <stdio.h>) to be 64-bit as well.
Collaboration diagram for File:
Structs