15 #include "vertexDataSaveFile.h" 16 #include "mutexHolder.h" 17 #include "clockObject.h" 18 #include "config_gobj.h" 21 #include <sys/types.h> 33 VertexDataSaveFile(
const Filename &directory,
const string &prefix,
38 if (directory.empty()) {
52 strm << prefix <<
"_" << index <<
".dat";
54 string basename = strm.str();
58 if (gobj_cat.is_debug()) {
60 <<
"Creating vertex data save file " << os_specific <<
"\n";
65 DWORD flags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS;
66 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) 68 flags |= FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;
70 _handle = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
71 0, NULL, CREATE_ALWAYS, flags, NULL);
72 if (_handle != INVALID_HANDLE_VALUE) {
79 DWORD err = GetLastError();
81 if (err != ERROR_SHARING_VIOLATION) {
88 <<
"Couldn't open vertex data save file.\n";
98 int flags = O_RDWR | O_CREAT;
99 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) 104 _fd = ::open(os_specific.c_str(), flags, 0666);
105 while (_fd == -1 && errno == EAGAIN) {
107 _fd = ::open(os_specific.c_str(), flags, 0666);
112 if (!_filename.
exists()) {
119 <<
"Couldn't open vertex data save file.\n";
132 int result = lockf(_fd, F_TLOCK, 0);
134 int result = flock(_fd, LOCK_EX | LOCK_NB);
139 if (ftruncate(_fd, 0) < 0) {
141 <<
"Couldn't truncate vertex data save file.\n";
150 unlink(os_specific.c_str());
169 ~VertexDataSaveFile() {
171 if (_handle != NULL) {
172 CloseHandle(_handle);
199 write_data(
const unsigned char *data,
size_t size,
bool compressed) {
208 _total_file_size = max(_total_file_size, block->get_start() + size);
209 block->set_compressed(compressed);
212 OVERLAPPED overlapped;
213 memset(&overlapped, 0,
sizeof(overlapped));
214 overlapped.Offset = block->get_start();
216 DWORD bytes_written = 0;
219 BOOL success = WriteFile(_handle, data, size, &bytes_written, &overlapped);
221 DWORD error = GetLastError();
222 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
228 <<
"Error writing " << size
229 <<
" bytes to save file, windows error code 0x" << hex
230 << error << dec <<
". Disk full?\n";
233 success = GetOverlappedResult(_handle, &overlapped, &bytes_written,
false);
235 nassertr(bytes_written == size, NULL);
237 if (gobj_cat.is_debug()) {
239 <<
"Wrote " << size <<
" bytes in " << *
Thread::get_current_thread() <<
" over " << floor((finish_time - start_time) * 1000.0) <<
" ms and " << num_passes <<
" passes.\n";
243 if (lseek(_fd, block->get_start(), SEEK_SET) == -1) {
245 <<
"Error seeking to position " << block->get_start() <<
" in save file.\n";
250 ssize_t result = ::write(_fd, data, size);
252 if (errno == EAGAIN) {
256 <<
"Error writing " << size <<
" bytes to save file. Disk full?\n";
286 nassertr(size == block->
get_size(),
false);
296 OVERLAPPED overlapped;
297 memset(&overlapped, 0,
sizeof(overlapped));
300 DWORD bytes_read = 0;
303 BOOL success = ReadFile(_handle, data, size, &bytes_read, &overlapped);
305 DWORD error = GetLastError();
306 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
312 <<
"Error reading " << size
313 <<
" bytes from save file, windows error code 0x" << hex
314 << error << dec <<
".\n";
317 success = GetOverlappedResult(_handle, &overlapped, &bytes_read,
false);
319 nassertr(bytes_read == size, NULL);
321 if (gobj_cat.is_debug()) {
323 <<
"Read " << size <<
" bytes in " << *
Thread::get_current_thread() <<
" over " << floor((finish_time - start_time) * 1000.0) <<
" ms and " << num_passes <<
" passes.\n";
328 if (lseek(_fd, block->
get_start(), SEEK_SET) == -1) {
330 <<
"Error seeking to position " << block->
get_start() <<
" in save file.\n";
334 ssize_t result = read(_fd, data, size);
336 if (errno == EAGAIN) {
340 <<
"Error reading " << size <<
" bytes from save file.\n";
361 make_block(
size_t start,
size_t size) {
A block of bytes on the save file.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
An implementation of a very simple block allocator.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
static void force_yield()
Suspends the current thread for the rest of the current epoch.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
A single block as returned from SimpleAllocator::alloc().
The name of a file, such as a texture file or an Egg file.
double get_real_time() const
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
static const Filename & get_temp_directory()
Returns a path to a system-defined temporary directory.
size_t get_start() const
Returns the starting point of this block.
bool read_data(unsigned char *data, size_t size, VertexDataSaveBlock *block)
Reads a block of data from the file, and returns true on success, false on failure.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
size_t get_size() const
Returns the size of this block.