Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Безразмерный саморасширяемый массив как некая неисчерпаемая виртуальная память

Пытаюсь сам реализовать безразмерный саморасширяемый массив, вначале на 2Gb, затем больше. Т.е. при обращении к элементу массива чтобы проверялось, есть ли кластер в оперативке, и выдавался кластер, если нет - чтобы кластер грузился из файла. Если кластеров много - менее используемые выгружались. Т.е. как некая неисчерпаемая виртуальная память. Цель - закешировать результат выборки из любой СУБД, например, если она вернула миллион строк.
Может, есть готовая библиотека реализующая это через IStream интерфейс работы с файлами, или что-то такое? Часть СУБД бывают 32bit, чтобы решение могло работать и в 32bit, и 64bit. VirtualAlloc не подходит (адресное пространство в 32bit ограничено).
В идеале нечто такое
class BigArea{
operator char& [] (__int64 index) { char * tmp_buff; //... return &tmp_buff[ index & 4095]; // Т.к. блок памяти 4096 байт. } }
Как источник "неисчерпаемой" памяти. Есть ли библиотека, которая позволит закешировать 2-4-10 Gb памяти, разместив "лишнее" на диске, а наиболее используемую память в оперативной памяти?


Ответ

Поскольку реализации до сих пор нету, собрал такой "скелет".
class TBigMem{ private: HANDLE hFile; HANDLE hMap; __int64 hIndex; //можно переназначить тип на тот, который в вашей IDE __int64 maxsize; void * mWnd; DWORD AllocationGranularity; // Размер кратным которого должно быть окно
bool DoMap(unsigned long * index){ if (hIndex >=0) UnmapViewOfFile(mWnd); hIndex = *(__int64*)index; void * wnd = MapViewOfFileEx(hMap, FILE_MAP_ALL_ACCESS, index[1], index[0],AllocationGranularity,mWnd); /*Окно*/ if (wnd == 0) wnd=MapViewOfFileEx(hMap,FILE_MAP_ALL_ACCESS, index[1], index[0],AllocationGranularity,NULL);/*Новое окно*/ if (wnd == 0) { /*Обработать ошибку - не хватает памяти скорее всего*/}; if (wnd!=0) mWnd = wnd; return wnd != 0; };

public: TBigMem (__int64 size) {// Размер можно сделать константой char buff[512]; SYSTEM_INFO si; GetSystemInfo(&si); AllocationGranularity = si.dwAllocationGranularity; GetTempPathA(sizeof(buff),buff); GetTempFileNameA(buff,"bigmem",0,buff); // Тут задать префикс для временного файла hFile = CreateFileA(buff,GENERIC_READ | GENERIC_WRITE ,0,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,0); hIndex = -1; Realloc(size); }
bool Realloc(__int64 size){ if (!hFile) return 0; if (hIndex >=0) UnmapViewOfFile(mWnd); if (hMap) CloseHandle(hMap); hMap = 0; hIndex = -1; hMap = CreateFileMappingA(hFile,0, PAGE_READWRITE, ((unsigned long*)&size)[1], ((unsigned long*)&size)[0] ,0); if (hMap !=0) maxsize = size; return hMap != 0; }
bool isValid() { return hMap !=0; };
~TBigMem(){ CloseHandle(hMap); CloseHandle(hFile); };
char& operator[](__int64 index){ union { __int64 i; unsigned long w[2]; } u; if (index >= maxsize)// Авторасширение с выравниванием Relloc(index - (index & AllocationGranularity)+AllocationGranularity); if (hMap == 0) return *(char*)NULL; // Не возможно, обработать ошибку unsigned long offs; int err = 0; u.i = index; offs = u.w[0] & (AllocationGranularity-1); u.w[0] &= ~(AllocationGranularity-1); //TODO: тут можно дописать сдвиг индекса, что б окно было шире if (u.i != hIndex) DoMap(&u.w[0]); //err = GetLastError(); return *((char*)mWnd + offs); };
unsigned int GetAvalible(__int64 index) { // Колличество байт, доступных в окне return AllocationGranularity-((unsigned int)(index & (AllocationGranularity-1))); } };
Протестировал на небольших обьёмах так:
char c; TBigMem data(1000000); data[0]=1; data[65536]=2; с = data[0]; // переключить на первую страницу с = data[65536]; // переключить другую станицу
Данные сохраняются. Пришлось разобраться с тем, как делать мапинг, с грануляцией страниц, с переключением отображения (во многих примерах переключения страниц отсутствует).
P.S. Ожидаю более удобную реализацию. На сейчас момент это единственный пример реализации.
Для char такое решение подходит, а для более емких типов нужно добавить "двойной" буфер, потому что при размере более одного байта тип может оказаться на "разрезе двух страниц". Я столкнулся с тем, что не нашёл толкового описания как зарезервировать память для MapViewOfFileEx. Для "расширеного" функционала, возможно нужны шаблоны template, это на будущее.

Комментариев нет:

Отправить комментарий