diff options
Diffstat (limited to 'plugins/Db3x_mmap/dbcache.c')
-rw-r--r-- | plugins/Db3x_mmap/dbcache.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/plugins/Db3x_mmap/dbcache.c b/plugins/Db3x_mmap/dbcache.c new file mode 100644 index 0000000000..8e177c6f6d --- /dev/null +++ b/plugins/Db3x_mmap/dbcache.c @@ -0,0 +1,206 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+BOOL safetyMode = TRUE;
+static UINT_PTR flushBuffersTimerId;
+
+static PBYTE pNull = 0;
+static PBYTE pDbCache = NULL;
+static HANDLE hMap = NULL;
+static DWORD dwFileSize = 0;
+static DWORD ChunkSize = 65536;
+static DWORD flushFailTick = 0;
+
+
+void Map()
+{
+ hMap = CreateFileMapping(hDbFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL);
+
+ if (hMap)
+ {
+ pDbCache = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS/*FILE_MAP_WRITE*/, 0, 0 ,0);
+ if (!pDbCache)
+ DatabaseCorruption( _T("%s (MapViewOfFile failed. Code: %d)"));
+ }
+ else
+ DatabaseCorruption( _T("%s (CreateFileMapping failed. Code: %d)"));
+}
+
+void ReMap(DWORD needed)
+{
+ KillTimer(NULL,flushBuffersTimerId);
+
+ log3("remapping %d + %d (file end: %d)",dwFileSize,needed,dbHeader.ofsFileEnd);
+
+ if (needed > ChunkSize)
+ {
+ if (needed + dwFileSize > dbHeader.ofsFileEnd + ChunkSize)
+ DatabaseCorruption( _T("%s (Too large increment)"));
+ else
+ {
+ DWORD x = dbHeader.ofsFileEnd/ChunkSize;
+ dwFileSize = (x+1)*ChunkSize;
+ }
+ }
+ else
+ dwFileSize += ChunkSize;
+
+// FlushViewOfFile(pDbCache, 0);
+ UnmapViewOfFile(pDbCache);
+ pDbCache = NULL;
+ CloseHandle(hMap);
+
+ Map();
+}
+
+void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes)
+{
+ int x = 0;
+ log3("move %d %08x->%08x",bytes,ofsSource,ofsDest);
+ if (ofsDest+bytes>dwFileSize) ReMap(ofsDest+bytes-dwFileSize);
+ if (ofsSource+bytes>dwFileSize) {
+ x = ofsSource+bytes-dwFileSize;
+ log0("buggy move!");
+ _ASSERT(0);
+ }
+ if (x > 0)
+ ZeroMemory(pDbCache+ofsDest+bytes-x, x);
+ if (ofsSource < dwFileSize)
+ MoveMemory(pDbCache+ofsDest,pDbCache+ofsSource, bytes-x);
+
+ logg();
+}
+
+//we are assumed to be in a mutex here
+PBYTE DBRead(DWORD ofs,int bytesRequired,int *bytesAvail)
+{
+ // buggy read
+ if (ofs>=dwFileSize) {
+ log2("read from outside %d@%08x",bytesRequired,ofs);
+ if (bytesAvail!=NULL) *bytesAvail = ChunkSize;
+ return pNull;
+ }
+ log3((ofs+bytesRequired>dwFileSize)?"read %d@%08x, only %d avaliable":"read %d@%08x",bytesRequired,ofs,dwFileSize-ofs);
+ if (bytesAvail!=NULL) *bytesAvail = dwFileSize - ofs;
+ return pDbCache+ofs;
+}
+
+//we are assumed to be in a mutex here
+void DBWrite(DWORD ofs,PVOID pData,int bytes)
+{
+ log2("write %d@%08x",bytes,ofs);
+ if (ofs+bytes>dwFileSize) ReMap(ofs+bytes-dwFileSize);
+ MoveMemory(pDbCache+ofs,pData,bytes);
+ logg();
+}
+
+//we are assumed to be in a mutex here
+void DBFill(DWORD ofs,int bytes)
+{
+ log2("zerofill %d@%08x",bytes,ofs);
+ if (ofs+bytes<=dwFileSize)
+ ZeroMemory(pDbCache+ofs,bytes);
+ logg();
+}
+
+static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime)
+{
+ if (!pDbCache) return;
+
+ KillTimer(NULL,flushBuffersTimerId);
+ log0("tflush1");
+ if (FlushViewOfFile(pDbCache, 0) == 0) {
+ if (flushFailTick == 0)
+ flushFailTick = GetTickCount();
+ else if (GetTickCount() - flushFailTick > 5000)
+ DatabaseCorruption(NULL);
+ }
+ else
+ flushFailTick = 0;
+ log0("tflush2");
+}
+
+void DBFlush(int setting)
+{
+ if(!setting) {
+ log0("nflush1");
+ if(safetyMode && pDbCache) {
+ if (FlushViewOfFile(pDbCache, 0) == 0) {
+ if (flushFailTick == 0)
+ flushFailTick = GetTickCount();
+ else if (GetTickCount() - flushFailTick > 5000)
+ DatabaseCorruption(NULL);
+ }
+ else
+ flushFailTick = 0;
+ }
+ log0("nflush2");
+ return;
+ }
+ KillTimer(NULL,flushBuffersTimerId);
+ flushBuffersTimerId=SetTimer(NULL,flushBuffersTimerId,50,DoBufferFlushTimerProc);
+}
+
+static INT_PTR CacheSetSafetyMode(WPARAM wParam,LPARAM lParam)
+{
+ EnterCriticalSection(&csDbAccess);
+ safetyMode=wParam;
+ LeaveCriticalSection(&csDbAccess);
+ DBFlush(1);
+ return 0;
+}
+
+int InitCache(void)
+{
+ DWORD x;
+ SYSTEM_INFO sinf;
+
+ GetSystemInfo(&sinf);
+ ChunkSize = sinf.dwAllocationGranularity;
+
+ dwFileSize = GetFileSize(hDbFile, NULL);
+
+ // Align to chunk
+ x = dwFileSize % ChunkSize;
+ if (x) dwFileSize += ChunkSize - x;
+
+ Map();
+
+ // zero region for reads outside the file
+ pNull = calloc(ChunkSize,1);
+
+ CreateServiceFunction(MS_DB_SETSAFETYMODE,CacheSetSafetyMode);
+
+ return 0;
+}
+
+void UninitCache(void)
+{
+ KillTimer(NULL,flushBuffersTimerId);
+ FlushViewOfFile(pDbCache, 0);
+ UnmapViewOfFile(pDbCache);
+ CloseHandle(hMap);
+ if (pNull) free(pNull);
+}
|