overlapped I/O
This commit is contained in:
parent
c79a08611f
commit
f19a1c7584
|
|
@ -49,5 +49,5 @@ get_num_pages() const {
|
|||
INLINE VertexDataPage *VertexDataBook::
|
||||
create_new_page(size_t size) {
|
||||
size_t page_size = ((size + _block_size - 1) / _block_size) * _block_size;
|
||||
return new VertexDataPage(this, page_size);
|
||||
return new VertexDataPage(this, page_size, _block_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,41 @@
|
|||
#include "vertexDataBook.h"
|
||||
#include "reMutexHolder.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
// Windows case.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
|
||||
// Posix case.
|
||||
#include <unistd.h>
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBook::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataBook::
|
||||
VertexDataBook(size_t block_size) : _block_size(block_size) {
|
||||
VertexDataBook(size_t block_size) {
|
||||
// Make sure the block_size is an integer multiple of the system's
|
||||
// page size.
|
||||
size_t system_page_size;
|
||||
#ifdef WIN32
|
||||
// Windows case.
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
|
||||
system_page_size = (size_t)sysinfo.dwPageSize;
|
||||
#else
|
||||
// Posix case.
|
||||
system_page_size = getpagesize();
|
||||
#endif // WIN32
|
||||
|
||||
_block_size = ((block_size + system_page_size - 1) / system_page_size) * system_page_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -231,6 +231,17 @@ set_ram_class(RamClass rclass) {
|
|||
adjust_book_size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::round_up
|
||||
// Access: Private
|
||||
// Description: Round page_size up to the next multiple of
|
||||
// _block_size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t VertexDataPage::
|
||||
round_up(size_t page_size) const {
|
||||
return ((page_size + _block_size - 1) / _block_size) * _block_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::PageThread::Constructor
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -27,6 +27,21 @@
|
|||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
// Windows case (VirtualAlloc)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
|
||||
// Posix case (mmap)
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#endif
|
||||
|
||||
ConfigVariableInt max_resident_vertex_data
|
||||
("max-resident-vertex-data", -1,
|
||||
PRC_DESC("Specifies the maximum number of bytes of all vertex data "
|
||||
|
|
@ -95,6 +110,7 @@ VertexDataPage(size_t book_size) :
|
|||
SimpleAllocator(book_size, _unused_mutex),
|
||||
SimpleLruPage(book_size),
|
||||
_book_size(book_size),
|
||||
_block_size(0),
|
||||
_book(NULL)
|
||||
{
|
||||
_page_data = NULL;
|
||||
|
|
@ -110,14 +126,15 @@ VertexDataPage(size_t book_size) :
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexDataPage::
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size) :
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size, size_t block_size) :
|
||||
SimpleAllocator(page_size, book->_lock),
|
||||
SimpleLruPage(page_size),
|
||||
_book_size(page_size),
|
||||
_block_size(block_size),
|
||||
_book(book)
|
||||
{
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)page_size);
|
||||
_page_data = new unsigned char[page_size];
|
||||
_allocated_size = round_up(page_size);
|
||||
_page_data = alloc_page_data(_allocated_size);
|
||||
_size = page_size;
|
||||
|
||||
_uncompressed_size = _size;
|
||||
|
|
@ -146,8 +163,7 @@ VertexDataPage::
|
|||
}
|
||||
|
||||
if (_page_data != NULL) {
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
delete[] _page_data;
|
||||
free_page_data(_page_data, _allocated_size);
|
||||
_size = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -322,7 +338,8 @@ make_resident() {
|
|||
<< "Expanding page from " << _size
|
||||
<< " to " << _uncompressed_size << "\n";
|
||||
}
|
||||
unsigned char *new_data = new unsigned char[_uncompressed_size];
|
||||
size_t new_allocated_size = round_up(_uncompressed_size);
|
||||
unsigned char *new_data = alloc_page_data(new_allocated_size);
|
||||
uLongf dest_len = _uncompressed_size;
|
||||
int result = uncompress(new_data, &dest_len, _page_data, _size);
|
||||
if (result != Z_OK) {
|
||||
|
|
@ -332,10 +349,10 @@ make_resident() {
|
|||
}
|
||||
nassertv(dest_len == _uncompressed_size);
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_uncompressed_size - (int)_size);
|
||||
delete[] _page_data;
|
||||
free_page_data(_page_data, _allocated_size);
|
||||
_page_data = new_data;
|
||||
_size = _uncompressed_size;
|
||||
_allocated_size = new_allocated_size;
|
||||
#endif
|
||||
|
||||
set_lru_size(_size);
|
||||
|
|
@ -383,14 +400,15 @@ make_compressed() {
|
|||
<< "Couldn't compress: zlib error " << result << "\n";
|
||||
nassert_raise("zlib error");
|
||||
}
|
||||
|
||||
unsigned char *new_data = new unsigned char[buffer_size];
|
||||
|
||||
size_t new_allocated_size = round_up(buffer_size);
|
||||
unsigned char *new_data = alloc_page_data(new_allocated_size);
|
||||
memcpy(new_data, buffer, buffer_size);
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)buffer_size - (int)_size);
|
||||
delete[] _page_data;
|
||||
free_page_data(_page_data, _allocated_size);
|
||||
_page_data = new_data;
|
||||
_size = buffer_size;
|
||||
_allocated_size = new_allocated_size;
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
|
|
@ -428,8 +446,7 @@ make_disk() {
|
|||
return;
|
||||
}
|
||||
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
delete[] _page_data;
|
||||
free_page_data(_page_data, _allocated_size);
|
||||
_page_data = NULL;
|
||||
_size = 0;
|
||||
|
||||
|
|
@ -461,7 +478,7 @@ do_save_to_disk() {
|
|||
|
||||
bool compressed = (_ram_class == RC_compressed);
|
||||
|
||||
_saved_block = get_save_file()->write_data(_page_data, _size, compressed);
|
||||
_saved_block = get_save_file()->write_data(_page_data, _allocated_size, compressed);
|
||||
if (_saved_block == (VertexDataSaveBlock *)NULL) {
|
||||
// Can't write it to disk. Too bad.
|
||||
return false;
|
||||
|
|
@ -500,15 +517,16 @@ do_restore_from_disk() {
|
|||
<< "Restoring page, " << buffer_size << " bytes, from disk\n";
|
||||
}
|
||||
|
||||
unsigned char *new_data = new unsigned char[buffer_size];
|
||||
if (!get_save_file()->read_data(new_data, buffer_size, _saved_block)) {
|
||||
size_t new_allocated_size = round_up(buffer_size);
|
||||
unsigned char *new_data = alloc_page_data(new_allocated_size);
|
||||
if (!get_save_file()->read_data(new_data, new_allocated_size, _saved_block)) {
|
||||
nassert_raise("read error");
|
||||
}
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)buffer_size);
|
||||
nassertv(_page_data == (unsigned char *)NULL);
|
||||
_page_data = new_data;
|
||||
_size = buffer_size;
|
||||
_allocated_size = new_allocated_size;
|
||||
|
||||
set_lru_size(_size);
|
||||
if (_saved_block->get_compressed()) {
|
||||
|
|
@ -606,6 +624,46 @@ make_save_file() {
|
|||
_save_file = new VertexDataSaveFile(vertex_save_file_directory,
|
||||
vertex_save_file_prefix, max_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::alloc_page_data
|
||||
// Access: Private
|
||||
// Description: Allocates and returns a freshly-allocated buffer of
|
||||
// at least the indicated size for holding vertex data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
unsigned char *VertexDataPage::
|
||||
alloc_page_data(size_t page_size) const {
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, page_size);
|
||||
|
||||
unsigned char *buffer;
|
||||
#ifdef WIN32
|
||||
// Windows case.
|
||||
buffer = (unsigned char *)VirtualAlloc(NULL, page_size, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE);
|
||||
#else
|
||||
// Posix case.
|
||||
buffer = (unsigned char *)mmap(NULL, page_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#endif
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::free_page_data
|
||||
// Access: Private
|
||||
// Description: Releases a buffer allocated via alloc_page_data().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataPage::
|
||||
free_page_data(unsigned char *page_data, size_t page_size) const {
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, page_size);
|
||||
|
||||
#ifdef WIN32
|
||||
VirtualFree(page_data, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(page_data, page_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataPage::PageThread::add_page
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class VertexDataBlock;
|
|||
class EXPCL_PANDA VertexDataPage : public SimpleAllocator, public SimpleLruPage {
|
||||
public:
|
||||
VertexDataPage(size_t book_size);
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size);
|
||||
VertexDataPage(VertexDataBook *book, size_t page_size, size_t block_size);
|
||||
~VertexDataPage();
|
||||
|
||||
PUBLISHED:
|
||||
|
|
@ -104,6 +104,10 @@ private:
|
|||
INLINE void set_ram_class(RamClass ram_class);
|
||||
static void make_save_file();
|
||||
|
||||
INLINE size_t round_up(size_t page_size) const;
|
||||
unsigned char *alloc_page_data(size_t page_size) const;
|
||||
void free_page_data(unsigned char *page_data, size_t page_size) const;
|
||||
|
||||
typedef pdeque<VertexDataPage *> PendingPages;
|
||||
|
||||
class PageThread : public Thread {
|
||||
|
|
@ -129,10 +133,11 @@ private:
|
|||
static Mutex _tlock; // Protects the thread members.
|
||||
|
||||
unsigned char *_page_data;
|
||||
size_t _size, _uncompressed_size;
|
||||
size_t _size, _allocated_size, _uncompressed_size;
|
||||
RamClass _ram_class;
|
||||
PT(VertexDataSaveBlock) _saved_block;
|
||||
size_t _book_size;
|
||||
size_t _block_size;
|
||||
|
||||
//Mutex _lock; // Inherited from SimpleAllocator. Protects above members.
|
||||
|
||||
|
|
|
|||
|
|
@ -63,10 +63,13 @@ VertexDataSaveFile(const Filename &directory, const string &prefix,
|
|||
|
||||
#ifdef _WIN32
|
||||
// Windows case.
|
||||
DWORD flags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS;
|
||||
#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
|
||||
// In SIMPLE_THREADS mode, we use "overlapped" I/O.
|
||||
flags |= FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;
|
||||
#endif
|
||||
_handle = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_RANDOM_ACCESS,
|
||||
NULL);
|
||||
0, NULL, CREATE_ALWAYS, flags, NULL);
|
||||
if (_handle != INVALID_HANDLE_VALUE) {
|
||||
// The file was successfully opened and locked.
|
||||
break;
|
||||
|
|
@ -194,19 +197,23 @@ write_data(const unsigned char *data, size_t size, bool compressed) {
|
|||
block->set_compressed(compressed);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (SetFilePointer(_handle, block->get_start(), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
|
||||
gobj_cat.error()
|
||||
<< "Error seeking to position " << block->get_start() << " in save file.\n";
|
||||
return false;
|
||||
}
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.Offset = block->get_start();
|
||||
|
||||
WriteFile(_handle, data, size, NULL, &overlapped);
|
||||
DWORD bytes_written;
|
||||
if (!WriteFile(_handle, data, size, &bytes_written, NULL) ||
|
||||
bytes_written != size) {
|
||||
gobj_cat.error()
|
||||
<< "Error writing " << size << " bytes to save file. Disk full?\n";
|
||||
return NULL;
|
||||
while (!GetOverlappedResult(_handle, &overlapped, &bytes_written, false)) {
|
||||
if (GetLastError() == ERROR_IO_INCOMPLETE) {
|
||||
// Wait for more later.
|
||||
Thread::force_yield();
|
||||
} else {
|
||||
gobj_cat.error()
|
||||
<< "Error writing " << size << " bytes to save file. Disk full?\n";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
nassertr(bytes_written == size, NULL);
|
||||
|
||||
#else
|
||||
// Posix case.
|
||||
|
|
@ -257,20 +264,23 @@ read_data(unsigned char *data, size_t size, VertexDataSaveBlock *block) {
|
|||
nassertr(size == block->get_size(), false);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (SetFilePointer(_handle, block->get_start(), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
|
||||
gobj_cat.error()
|
||||
<< "Error seeking to position " << block->get_start() << " in save file.\n";
|
||||
return false;
|
||||
}
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.Offset = block->get_start();
|
||||
|
||||
ReadFile(_handle, data, size, NULL, &overlapped);
|
||||
DWORD bytes_read;
|
||||
if (!ReadFile(_handle, data, size, &bytes_read, NULL) ||
|
||||
bytes_read != size) {
|
||||
gobj_cat.error()
|
||||
<< "Error writing " << size << " bytes to save file. Disk full?\n";
|
||||
delete block;
|
||||
return NULL;
|
||||
while (!GetOverlappedResult(_handle, &overlapped, &bytes_read, false)) {
|
||||
if (GetLastError() == ERROR_IO_INCOMPLETE) {
|
||||
// Wait for more later.
|
||||
Thread::force_yield();
|
||||
} else {
|
||||
gobj_cat.error()
|
||||
<< "Error reading " << size << " bytes from save file.\n";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
nassertr(bytes_read == size, NULL);
|
||||
|
||||
#else
|
||||
// Posix case.
|
||||
|
|
|
|||
Loading…
Reference in New Issue