summaryrefslogtreecommitdiff
path: root/db3x_autobackups/dbcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'db3x_autobackups/dbcache.c')
-rw-r--r--db3x_autobackups/dbcache.c248
1 files changed, 110 insertions, 138 deletions
diff --git a/db3x_autobackups/dbcache.c b/db3x_autobackups/dbcache.c
index dd3bc5a..601670d 100644
--- a/db3x_autobackups/dbcache.c
+++ b/db3x_autobackups/dbcache.c
@@ -2,8 +2,8 @@
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
+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
@@ -22,165 +22,124 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commonheaders.h"
-#include "database.h"
+BOOL safetyMode = TRUE;
+static int flushBuffersTimerId;
-#define CACHESECTIONSIZE 4096
-#define CACHESECTIONCOUNT 32
-
-extern HANDLE hDbFile;
-extern CRITICAL_SECTION csDbAccess;
+static PBYTE pNull = 0;
+static PBYTE pDbCache = NULL;
+static HANDLE hMap = NULL;
+static DWORD dwFileSize = 0;
+static DWORD ChunkSize = 65536;
-static BOOL safetyMode=TRUE;
-static PBYTE pDbCache;
-static DWORD lastUseCounter;
-struct DBCacheSectionInfo {
- DWORD ofsBase;
- DWORD lastUsed;
-} static cacheSectionInfo[CACHESECTIONCOUNT];
-static __inline int FindSectionForOffset(const DWORD ofs)
+void Map()
{
- int i;
- for(i=0;i<CACHESECTIONCOUNT;i++)
- if(ofs>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE)
- return i;
- return -1;
-}
+ hMap = CreateFileMapping(hDbFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL);
-static __inline int FindLRUSection(void)
-{
- int i,lru=0;
- DWORD lowestLastUse=cacheSectionInfo[0].lastUsed;
- for(i=1;i<CACHESECTIONCOUNT;i++) if(cacheSectionInfo[i].lastUsed<lowestLastUse) {lru=i; lowestLastUse=cacheSectionInfo[i].lastUsed;}
- return lru;
+ if (hMap)
+ pDbCache = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS/*FILE_MAP_WRITE*/, 0, 0 ,0);
+ else
+ DatabaseCorruption("%s (CreateFileMapping failed. Code: %d)");
+
+ if (!pDbCache)
+ DatabaseCorruption("%s (MapViewOfFile failed. Code: %d)");
}
-static __inline void LoadSection(const int i,DWORD ofs)
+void UnMap()
{
- cacheSectionInfo[i].ofsBase=ofs-ofs%CACHESECTIONSIZE;
- log1("readsect %08x",ofs);
- SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
- ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&ofs,NULL);
+ KillTimer(NULL,flushBuffersTimerId);
+// FlushViewOfFile(pDbCache, 0);
+ UnmapViewOfFile(pDbCache);
+ pDbCache = NULL;
+ CloseHandle(hMap);
}
-static __inline void MoveSection(int *sectId,int dest)
+void ReMap(DWORD needed)
{
- CopyMemory(pDbCache+dest*CACHESECTIONSIZE,pDbCache+(*sectId)*CACHESECTIONSIZE,CACHESECTIONSIZE);
- cacheSectionInfo[dest].ofsBase=cacheSectionInfo[*sectId].ofsBase;
- *sectId=dest;
+ KillTimer(NULL,flushBuffersTimerId);
+
+ log3("remapping %d + %d (file end: %d)",dwFileSize,needed,dbHeader.ofsFileEnd);
+
+ if (needed > ChunkSize)
+ {
+ if ((needed + dwFileSize) - dbHeader.ofsFileEnd > ChunkSize)
+ DatabaseCorruption("%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)
{
-
- int part1sect;
- int part2sect;
-
-
- part1sect = FindSectionForOffset(ofs);
- if (ofs%CACHESECTIONSIZE+bytesRequired<CACHESECTIONSIZE) {
- //only one section required
- if(part1sect==-1) {
- part1sect=FindLRUSection();
- LoadSection(part1sect,ofs);
- }
- cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
- if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect].ofsBase+CACHESECTIONSIZE-ofs;
- return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
- }
- //two sections are required
- part2sect=FindSectionForOffset(ofs+CACHESECTIONSIZE);
- if(part1sect!=-1) {
- if(part2sect==-1) { //first part in cache, but not second part
- if(part1sect==CACHESECTIONCOUNT-1) MoveSection(&part1sect,0);
- LoadSection(part1sect+1,ofs+CACHESECTIONSIZE);
- }
- else if(part2sect!=part1sect+1) { //both parts are in cache, but not already consecutive
- if(part1sect==CACHESECTIONCOUNT-1) {
- //first part is at end, move to before second part
- if(part2sect==0) //second part is at start: need to move both
- MoveSection(&part2sect,1);
- MoveSection(&part1sect,part2sect-1);
- }
- else //move second part to after first part
- MoveSection(&part2sect,part1sect+1);
- }
- }
- else {
- if(part2sect==-1) { //neither section is in cache
- part1sect=0; part2sect=1;
- LoadSection(part1sect,ofs); LoadSection(part2sect,ofs+CACHESECTIONSIZE);
- }
- else { //part 2 is in cache, but not part 1
- if(part2sect==0) MoveSection(&part2sect,1);
- part1sect=part2sect-1;
- LoadSection(part1sect,ofs);
- }
+ // buggy read
+ if (ofs>=dwFileSize) {
+ log2("read from outside %d@%08x",bytesRequired,ofs);
+ if (bytesAvail!=NULL) *bytesAvail = ChunkSize;
+ return pNull;
}
- //both sections are now consecutive, starting at part1sect
- cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
- cacheSectionInfo[part1sect+1].lastUsed=++lastUseCounter;
- if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect+1].ofsBase+CACHESECTIONSIZE-ofs;
- return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
+ 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)
{
- //write direct, and rely on Windows' write caching
- DWORD bytesWritten;
- int i;
-
log2("write %d@%08x",bytes,ofs);
- SetFilePointer(hDbFile,ofs,NULL,FILE_BEGIN);
- if (WriteFile(hDbFile,pData,bytes,&bytesWritten,NULL)==0)
- {
- DatabaseCorruption();
- }
+ if (ofs+bytes>dwFileSize) ReMap(ofs+bytes-dwFileSize);
+ MoveMemory(pDbCache+ofs,pData,bytes);
logg();
- //check if any of the cache sections contain this bit
- for(i=0;i<CACHESECTIONCOUNT;i++) {
- if(ofs+bytes>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) {
- if(ofs<cacheSectionInfo[i].ofsBase) { //don't start at beginning
- if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
- CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,CACHESECTIONSIZE);
- else CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,bytes-(cacheSectionInfo[i].ofsBase-ofs));
- }
- else { //start at beginning
- if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
- CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE-ofs);
- else CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,bytes);
- }
- }
- }
}
-void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes)
+//we are assumed to be in a mutex here
+void DBFill(DWORD ofs,int bytes)
{
- DWORD bytesRead;
- PBYTE buf;
-
- log3("move %d %08x->%08x",bytes,ofsSource,ofsDest);
- buf=(PBYTE)mir_alloc(bytes);
- SetFilePointer(hDbFile,ofsSource,NULL,FILE_BEGIN);
- ReadFile(hDbFile,buf,bytes,&bytesRead,NULL);
- DBWrite(ofsDest,buf,bytes);
- mir_free(buf);
+ log2("zerofill %d@%08x",bytes,ofs);
+ if (ofs+bytes<=dwFileSize)
+ ZeroMemory(pDbCache+ofs,bytes);
logg();
}
-static int flushBuffersTimerId;
static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd,UINT message,UINT idEvent,DWORD dwTime)
{
+ if (!pDbCache) return;
+
KillTimer(NULL,flushBuffersTimerId);
log0("tflush1");
- FlushFileBuffers(hDbFile);
+ if (FlushViewOfFile(pDbCache, 0) == 0)
+ DatabaseCorruption(NULL);
log0("tflush2");
}
@@ -188,7 +147,10 @@ void DBFlush(int setting)
{
if(!setting) {
log0("nflush1");
- if(safetyMode) FlushFileBuffers(hDbFile);
+ if(safetyMode && pDbCache) {
+ if (FlushViewOfFile(pDbCache, 0) == 0)
+ DatabaseCorruption(NULL);
+ }
log0("nflush2");
return;
}
@@ -201,29 +163,39 @@ static int CacheSetSafetyMode(WPARAM wParam,LPARAM lParam)
EnterCriticalSection(&csDbAccess);
safetyMode=wParam;
LeaveCriticalSection(&csDbAccess);
- if(safetyMode) FlushFileBuffers(hDbFile);
+ DBFlush(1);
return 0;
}
int InitCache(void)
{
- int i;
- DWORD bytesRead;
-
+ 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);
- pDbCache=(PBYTE)mir_alloc(CACHESECTIONSIZE*CACHESECTIONCOUNT);
- lastUseCounter=CACHESECTIONCOUNT;
- for(i=0;i<CACHESECTIONCOUNT;i++) {
- cacheSectionInfo[i].ofsBase=0;
- cacheSectionInfo[i].lastUsed=i;
- SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
- ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&bytesRead,NULL);
- }
+
return 0;
}
void UninitCache(void)
{
- mir_free(pDbCache);
KillTimer(NULL,flushBuffersTimerId);
+ FlushViewOfFile(pDbCache, 0);
+ UnmapViewOfFile(pDbCache);
+ CloseHandle(hMap);
+ if (pNull) free(pNull);
}