00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "vertexDataSaveFile.h"
00016 #include "mutexHolder.h"
00017 #include "clockObject.h"
00018
00019 #ifndef _WIN32
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <fcntl.h>
00023 #include <errno.h>
00024 #endif // _WIN32
00025
00026
00027
00028
00029
00030
00031 VertexDataSaveFile::
00032 VertexDataSaveFile(const Filename &directory, const string &prefix,
00033 size_t max_size) :
00034 SimpleAllocator(max_size, _lock)
00035 {
00036 Filename dir;
00037 if (directory.empty()) {
00038 dir = Filename::get_temp_directory();
00039 } else {
00040 dir = directory;
00041 }
00042
00043 _is_valid = false;
00044 _total_file_size = 0;
00045
00046
00047 int index = 0;
00048 while (true) {
00049 ++index;
00050 ostringstream strm;
00051 strm << prefix << "_" << index << ".dat";
00052
00053 string basename = strm.str();
00054 _filename = Filename(dir, basename);
00055 string os_specific = _filename.to_os_specific();
00056
00057 if (gobj_cat.is_debug()) {
00058 gobj_cat.debug()
00059 << "Creating vertex data save file " << os_specific << "\n";
00060 }
00061
00062 #ifdef _WIN32
00063
00064 DWORD flags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS;
00065 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
00066
00067 flags |= FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;
00068 #endif
00069 _handle = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
00070 0, NULL, CREATE_ALWAYS, flags, NULL);
00071 if (_handle != INVALID_HANDLE_VALUE) {
00072
00073 break;
00074
00075 } else {
00076
00077
00078 DWORD err = GetLastError();
00079
00080 if (err != ERROR_SHARING_VIOLATION) {
00081
00082 if (!dir.empty()) {
00083
00084 dir = Filename();
00085 } else {
00086 gobj_cat.error()
00087 << "Couldn't open vertex data save file.\n";
00088 return;
00089 }
00090 }
00091
00092
00093 }
00094
00095 #else
00096
00097 int flags = O_RDWR | O_CREAT;
00098 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
00099
00100 flags |= O_NONBLOCK;
00101 #endif
00102
00103 _fd = ::open(os_specific.c_str(), flags, 0666);
00104 while (_fd == -1 && errno == EAGAIN) {
00105 Thread::force_yield();
00106 _fd = ::open(os_specific.c_str(), flags, 0666);
00107 }
00108
00109 if (_fd == -1) {
00110
00111 if (!_filename.exists()) {
00112
00113 if (!dir.empty()) {
00114
00115 dir = Filename();
00116 } else {
00117 gobj_cat.error()
00118 << "Couldn't open vertex data save file.\n";
00119 return;
00120 }
00121 }
00122
00123
00124
00125 continue;
00126 }
00127
00128
00129
00130 int result = lockf(_fd, F_TLOCK, 0);
00131 if (result == 0) {
00132
00133
00134 if (ftruncate(_fd, 0) < 0) {
00135 gobj_cat.warning()
00136 << "Couldn't truncate vertex data save file.\n";
00137 }
00138
00139
00140
00141
00142
00143
00144
00145 unlink(os_specific.c_str());
00146 _filename = Filename();
00147 break;
00148 }
00149
00150
00151 close(_fd);
00152 #endif // _WIN32
00153 }
00154
00155 _is_valid = true;
00156 }
00157
00158
00159
00160
00161
00162
00163 VertexDataSaveFile::
00164 ~VertexDataSaveFile() {
00165 #ifdef _WIN32
00166 if (_handle != NULL) {
00167 CloseHandle(_handle);
00168 }
00169 #else
00170 if (_fd != -1) {
00171 close(_fd);
00172 }
00173 #endif // _WIN32
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 PT(VertexDataSaveBlock) VertexDataSaveFile::
00194 write_data(const unsigned char *data, size_t size, bool compressed) {
00195 MutexHolder holder(_lock);
00196
00197 if (!_is_valid) {
00198 return NULL;
00199 }
00200
00201 PT(VertexDataSaveBlock) block = (VertexDataSaveBlock *)SimpleAllocator::do_alloc(size);
00202 if (block != (VertexDataSaveBlock *)NULL) {
00203 _total_file_size = max(_total_file_size, block->get_start() + size);
00204 block->set_compressed(compressed);
00205
00206 #ifdef _WIN32
00207 OVERLAPPED overlapped;
00208 memset(&overlapped, 0, sizeof(overlapped));
00209 overlapped.Offset = block->get_start();
00210
00211 DWORD bytes_written = 0;
00212 double start_time = ClockObject::get_global_clock()->get_real_time();
00213 int num_passes = 0;
00214 BOOL success = WriteFile(_handle, data, size, &bytes_written, &overlapped);
00215 while (!success) {
00216 DWORD error = GetLastError();
00217 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
00218
00219 Thread::force_yield();
00220 ++num_passes;
00221 } else {
00222 gobj_cat.error()
00223 << "Error writing " << size
00224 << " bytes to save file, windows error code 0x" << hex
00225 << error << dec << ". Disk full?\n";
00226 return NULL;
00227 }
00228 success = GetOverlappedResult(_handle, &overlapped, &bytes_written, false);
00229 }
00230 nassertr(bytes_written == size, NULL);
00231 double finish_time = ClockObject::get_global_clock()->get_real_time();
00232 if (gobj_cat.is_debug()) {
00233 gobj_cat.debug()
00234 << "Wrote " << size << " bytes in " << *Thread::get_current_thread() << " over " << floor((finish_time - start_time) * 1000.0) << " ms and " << num_passes << " passes.\n";
00235 }
00236 #else
00237
00238 if (lseek(_fd, block->get_start(), SEEK_SET) == -1) {
00239 gobj_cat.error()
00240 << "Error seeking to position " << block->get_start() << " in save file.\n";
00241 return NULL;
00242 }
00243
00244 while (size > 0) {
00245 ssize_t result = ::write(_fd, data, size);
00246 if (result < 0) {
00247 if (errno == EAGAIN) {
00248 Thread::force_yield();
00249 } else {
00250 gobj_cat.error()
00251 << "Error writing " << size << " bytes to save file. Disk full?\n";
00252 return NULL;
00253 }
00254 continue;
00255 }
00256
00257 Thread::consider_yield();
00258 data += result;
00259 size -= result;
00260 }
00261 #endif // _WIN32
00262 }
00263
00264 return block;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 bool VertexDataSaveFile::
00274 read_data(unsigned char *data, size_t size, VertexDataSaveBlock *block) {
00275 MutexHolder holder(_lock);
00276
00277 if (!_is_valid) {
00278 return false;
00279 }
00280
00281 nassertr(size == block->get_size(), false);
00282
00283
00284
00285
00286
00287
00288
00289
00290 #ifdef _WIN32
00291 OVERLAPPED overlapped;
00292 memset(&overlapped, 0, sizeof(overlapped));
00293 overlapped.Offset = block->get_start();
00294
00295 DWORD bytes_read = 0;
00296 double start_time = ClockObject::get_global_clock()->get_real_time();
00297 int num_passes = 0;
00298 BOOL success = ReadFile(_handle, data, size, &bytes_read, &overlapped);
00299 while (!success) {
00300 DWORD error = GetLastError();
00301 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
00302
00303 Thread::force_yield();
00304 ++num_passes;
00305 } else {
00306 gobj_cat.error()
00307 << "Error reading " << size
00308 << " bytes from save file, windows error code 0x" << hex
00309 << error << dec << ".\n";
00310 return NULL;
00311 }
00312 success = GetOverlappedResult(_handle, &overlapped, &bytes_read, false);
00313 }
00314 nassertr(bytes_read == size, NULL);
00315 double finish_time = ClockObject::get_global_clock()->get_real_time();
00316 if (gobj_cat.is_debug()) {
00317 gobj_cat.debug()
00318 << "Read " << size << " bytes in " << *Thread::get_current_thread() << " over " << floor((finish_time - start_time) * 1000.0) << " ms and " << num_passes << " passes.\n";
00319 }
00320
00321 #else
00322
00323 if (lseek(_fd, block->get_start(), SEEK_SET) == -1) {
00324 gobj_cat.error()
00325 << "Error seeking to position " << block->get_start() << " in save file.\n";
00326 return false;
00327 }
00328 while (size > 0) {
00329 ssize_t result = read(_fd, data, size);
00330 if (result == -1) {
00331 if (errno == EAGAIN) {
00332 Thread::force_yield();
00333 } else {
00334 gobj_cat.error()
00335 << "Error reading " << size << " bytes from save file.\n";
00336 return false;
00337 }
00338 }
00339
00340 Thread::consider_yield();
00341 data += result;
00342 size -= result;
00343 }
00344 #endif // _WIN32
00345
00346 return true;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 SimpleAllocatorBlock *VertexDataSaveFile::
00356 make_block(size_t start, size_t size) {
00357 return new VertexDataSaveBlock(this, start, size);
00358 }
00359