-C Simplifications\sto\sthe\sSQLITE_PAGECACHE_BLOCKALLOC\slogic.\s\sReduce\sthe\snumber\nof\sdifficult-to-reach\sbranches.
-D 2011-08-23T23:41:40.811
+C Changes\sto\stest_quota.c\sto\smake\squota\sgroups\spersistent\seven\safter\sfiles\nare\sclosed.\s\sFiles\sremain\sa\spart\sof\sthe\squota\sgroup\suntil\sthey\sare\ndeleted.
+D 2011-08-24T01:25:55.043
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 8c930e7b493d59099ea1304bd0f2aed152eb3315
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
-F src/test_quota.c cc4f67e12558a252ea4a11720be268348f4b1595
+F src/test_quota.c e3a72c73bae28470ebece837b73d960f5a252878
F src/test_rtree.c 30c981837445a4e187ee850a49c4760d9642f7c3
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
-F test/quota.test 9535e220ad10ac1cdc49e246a53f080056f41141
+F test/quota.test dd8f0e0eb77bc206c1ad1b1494f4fe2fe6985183
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings.sh 2ebae31e1eb352696f3c2f7706a34c084b28c262
-P 880b51150aaed804005f5062b4dd2fa0ffafa147
-R 690091bd4eec428f02b835dd5a4096b1
+P d5d835fe8352cb2009133246d4ed1cd310803f75
+R 2328973d91120b14c5ab36809b3bc4cb
U drh
-Z a67c28a746ea7a9568474b8f0d071914
+Z 9f91d97e63ce42debeb18d7ad0c4d84a
quotaGroup *pGroup; /* Quota group to which this file belongs */
sqlite3_int64 iSize; /* Current size of this file */
int nRef; /* Number of times this file is open */
+ int deleteOnClose; /* True to delete this file when it closes */
quotaFile *pNext, **ppPrev; /* Linked list of files in the same group */
};
static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); }
static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); }
+/* Count the number of open files in a quotaGroup
+*/
+static int quotaGroupOpenFileCount(quotaGroup *pGroup){
+ int N = 0;
+ quotaFile *pFile = pGroup->pFiles;
+ while( pFile ){
+ if( pFile->nRef ) N++;
+ pFile = pFile->pNext;
+ }
+ return N;
+}
+
+/* Remove a file from a quota group.
+*/
+static void quotaRemoveFile(quotaFile *pFile){
+ quotaGroup *pGroup = pFile->pGroup;
+ pGroup->iSize -= pFile->iSize;
+ *pFile->ppPrev = pFile->pNext;
+ if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev;
+ sqlite3_free(pFile);
+}
+
+/* Remove all files from a quota group. It is always the case that
+** all files will be closed when this routine is called.
+*/
+static void quotaRemoveAllFiles(quotaGroup *pGroup){
+ while( pGroup->pFiles ){
+ assert( pGroup->pFiles->nRef==0 );
+ quotaRemoveFile(pGroup->pFiles);
+ }
+}
+
/* If the reference count and threshold for a quotaGroup are both
** zero, then destroy the quotaGroup.
*/
static void quotaGroupDeref(quotaGroup *pGroup){
- if( pGroup->pFiles==0 && pGroup->iLimit==0 ){
+ if( pGroup->iLimit==0 && quotaGroupOpenFileCount(pGroup)==0 ){
+ quotaRemoveAllFiles(pGroup);
*pGroup->ppPrev = pGroup->pNext;
if( pGroup->pNext ) pGroup->pNext->ppPrev = pGroup->ppPrev;
if( pGroup->xDestroy ) pGroup->xDestroy(pGroup->pArg);
return (sqlite3_file*)&p[1];
}
+/* Find a file in a quota group and return a pointer to that file.
+** Return NULL if the file is not in the group.
+*/
+static quotaFile *quotaFindFile(quotaGroup *pGroup, const char *zName){
+ quotaFile *pFile = pGroup->pFiles;
+ while( pFile && strcmp(pFile->zFilename, zName)!=0 ){
+ pFile = pFile->pNext;
+ }
+ return pFile;
+}
+
/************************* VFS Method Wrappers *****************************/
/*
** This is the xOpen method used for the "quota" VFS.
pSubOpen = quotaSubOpen(pConn);
rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags);
if( rc==SQLITE_OK ){
- for(pFile=pGroup->pFiles; pFile && strcmp(pFile->zFilename, zName);
- pFile=pFile->pNext){}
+ pFile = quotaFindFile(pGroup, zName);
if( pFile==0 ){
int nName = strlen(zName);
pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 );
pFile->ppPrev = &pGroup->pFiles;
pGroup->pFiles = pFile;
pFile->pGroup = pGroup;
+ pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0;
}
pFile->nRef++;
pQuotaOpen->pFile = pFile;
return rc;
}
+/*
+** This is the xDelete method used for the "quota" VFS.
+**
+** If the file being deleted is part of the quota group, then reduce
+** the size of the quota group accordingly. And remove the file from
+** the set of files in the quota group.
+*/
+static int quotaDelete(
+ sqlite3_vfs *pVfs, /* The quota VFS */
+ const char *zName, /* Name of file to be deleted */
+ int syncDir /* Do a directory sync after deleting */
+){
+ int rc; /* Result code */
+ quotaFile *pFile; /* Files in the quota */
+ quotaGroup *pGroup; /* The group file belongs to */
+ sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */
+
+ /* Do the actual file delete */
+ rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
+
+ /* If the file just deleted is a member of a quota group, then remove
+ ** it from that quota group.
+ */
+ if( rc==SQLITE_OK ){
+ quotaEnter();
+ pGroup = quotaGroupFind(zName);
+ if( pGroup ){
+ pFile = quotaFindFile(pGroup, zName);
+ if( pFile ){
+ if( pFile->nRef ){
+ pFile->deleteOnClose = 1;
+ }else{
+ quotaRemoveFile(pFile);
+ quotaGroupDeref(pGroup);
+ }
+ }
+ }
+ quotaLeave();
+ }
+ return rc;
+}
+
+
/************************ I/O Method Wrappers *******************************/
/* xClose requests get passed through to the original VFS. But we
pFile->nRef--;
if( pFile->nRef==0 ){
quotaGroup *pGroup = pFile->pGroup;
- pGroup->iSize -= pFile->iSize;
- if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev;
- *pFile->ppPrev = pFile->pNext;
+ if( pFile->deleteOnClose ) quotaRemoveFile(pFile);
quotaGroupDeref(pGroup);
- sqlite3_free(pFile);
}
quotaLeave();
return rc;
gQuota.pOrigVfs = pOrigVfs;
gQuota.sThisVfs = *pOrigVfs;
gQuota.sThisVfs.xOpen = quotaOpen;
+ gQuota.sThisVfs.xDelete = quotaDelete;
gQuota.sThisVfs.szOsFile += sizeof(quotaConn);
gQuota.sThisVfs.zName = "quota";
gQuota.sIoMethodsV1.iVersion = 1;
** All SQLite database connections must be closed before calling this
** routine.
**
-** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly one while
+** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
** shutting down in order to free all remaining quota groups.
*/
int sqlite3_quota_shutdown(void){
quotaGroup *pGroup;
if( gQuota.isInitialized==0 ) return SQLITE_MISUSE;
for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){
- if( pGroup->pFiles ) return SQLITE_MISUSE;
+ if( quotaGroupOpenFileCount(pGroup)>0 ) return SQLITE_MISUSE;
}
while( gQuota.pGroup ){
pGroup = gQuota.pGroup;
gQuota.pGroup = pGroup->pNext;
pGroup->iLimit = 0;
+ assert( quotaGroupOpenFileCount(pGroup)==0 );
quotaGroupDeref(pGroup);
}
gQuota.isInitialized = 0;
Tcl_NewWideIntObj(pFile->iSize));
Tcl_ListObjAppendElement(interp, pFileTerm,
Tcl_NewWideIntObj(pFile->nRef));
+ Tcl_ListObjAppendElement(interp, pFileTerm,
+ Tcl_NewWideIntObj(pFile->deleteOnClose));
Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm);
}
Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);