From: drh Date: Wed, 24 Aug 2011 01:25:55 +0000 (+0000) Subject: Changes to test_quota.c to make quota groups persistent even after files X-Git-Tag: version-3.7.8~55 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=796af156c7ba43649dd74cf21be7a389f44eec62;p=thirdparty%2Fsqlite.git Changes to test_quota.c to make quota groups persistent even after files are closed. Files remain a part of the quota group until they are deleted. FossilOrigin-Name: 04111ce980df9692b7fe65a36105e7de9627a3bb --- diff --git a/manifest b/manifest index 6323eabd43..16af0d39ef 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 @@ -219,7 +219,7 @@ F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e 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 @@ -626,7 +626,7 @@ F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea 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 @@ -961,7 +961,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5 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 diff --git a/manifest.uuid b/manifest.uuid index 32875c869f..a8d9586f0b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d5d835fe8352cb2009133246d4ed1cd310803f75 \ No newline at end of file +04111ce980df9692b7fe65a36105e7de9627a3bb \ No newline at end of file diff --git a/src/test_quota.c b/src/test_quota.c index 9b0e4a9ddc..faf4095559 100644 --- a/src/test_quota.c +++ b/src/test_quota.c @@ -95,6 +95,7 @@ struct quotaFile { 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 */ }; @@ -164,12 +165,45 @@ static struct { 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); @@ -276,6 +310,17 @@ static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){ 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. @@ -319,8 +364,7 @@ static int quotaOpen( 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 ); @@ -337,6 +381,7 @@ static int quotaOpen( pFile->ppPrev = &pGroup->pFiles; pGroup->pFiles = pFile; pFile->pGroup = pGroup; + pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0; } pFile->nRef++; pQuotaOpen->pFile = pFile; @@ -351,6 +396,49 @@ static int quotaOpen( 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 @@ -367,11 +455,8 @@ static int quotaClose(sqlite3_file *pConn){ 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; @@ -586,6 +671,7 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){ 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; @@ -617,19 +703,20 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){ ** 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; @@ -917,6 +1004,8 @@ static int test_quota_dump( 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); diff --git a/test/quota.test b/test/quota.test index 55eca2d538..469bc49016 100644 --- a/test/quota.test +++ b/test/quota.test @@ -223,7 +223,7 @@ do_test quota-3.2.X { } {SQLITE_OK} #------------------------------------------------------------------------- -# Quotas are deleted when unused and when there limit is set to zero +# Quotas are deleted when unused and when their limit is set to zero # # Return a list of all currently defined quotas. Each quota is identified @@ -330,10 +330,39 @@ do_test quota-4.3.1 { } {} do_test quota-4.4.1 { + set ::quota {} + sqlite3_quota_set */quota-test-A?.db 10000 quota_callback + file delete -force ./quota-test-A1.db ./quota-test-A2.db + sqlite3 db ./quota-test-A1.db + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(5000)); + } + quota_list +} {*/quota-test-A?.db} +do_test quota-4.4.2 { + expr {$::quota==""} +} {1} +do_test quota-4.4.3 { + db close + sqlite3 db ./quota-test-A2.db + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(5000)); + } + quota_list +} {*/quota-test-A?.db} +do_test quota-4.4.4 { + expr {$::quota!=""} +} {1} + + +do_test quota-4.9.1 { + db close sqlite3_quota_set A 1000 quota_callback sqlite3_quota_shutdown } {SQLITE_OK} -do_test quota-4.4.2 { +do_test quota-4.9.2 { quota_list } {}