Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add some very simple test cases (and resulting bug fixes) for release_memory(). (CVS 2826) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
154282fca54bf03d310d6931660f9980 |
User & Date: | danielk1977 2005-12-19 14:18:11.000 |
Context
2005-12-19
| ||
16:15 | Tentative fix for ticket #1567: disable the sqlite3pager_dont_write() optimization when a statement transaction is active. We continue to look for a better fix. (CVS 2827) (check-in: e6106cc133 user: drh tags: trunk) | |
14:18 | Add some very simple test cases (and resulting bug fixes) for release_memory(). (CVS 2826) (check-in: 154282fca5 user: danielk1977 tags: trunk) | |
2005-12-18
| ||
08:51 | Add the (untested) sqlite3_release_memory() function. (CVS 2825) (check-in: 345addaa03 user: danielk1977 tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.226 2005/12/19 14:18:11 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 | pPg = pPager->pFirstSynced; /* If we could not find a page that does not require an fsync() ** on the journal file then fsync the journal file. This is a ** very slow operation, so we work hard to avoid it. But sometimes ** it can't be helped. */ | | | 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 | pPg = pPager->pFirstSynced; /* If we could not find a page that does not require an fsync() ** on the journal file then fsync the journal file. This is a ** very slow operation, so we work hard to avoid it. But sometimes ** it can't be helped. */ if( pPg==0 && pPager->pFirst && syncOk ){ int rc = syncJournal(pPager); if( rc!=0 ){ sqlite3pager_rollback(pPager); return SQLITE_IOERR; } if( pPager->fullSync ){ /* If in full-sync mode, write a new journal header into the |
︙ | ︙ | |||
2389 2390 2391 2392 2393 2394 2395 | /* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated ** by the current thread may be sqliteFree()ed. ** ** nReq is the number of bytes of memory required. Once this much has | | > > | | | > | | | | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | /* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated ** by the current thread may be sqliteFree()ed. ** ** nReq is the number of bytes of memory required. Once this much has ** been released, the function returns. A negative value for nReq means ** free as much memory as possible. The return value is the total number ** of bytes of memory released. */ #ifndef SQLITE_OMIT_MEMORY_MANAGEMENT int sqlite3pager_release_memory(int nReq){ SqliteTsd *pTsd = sqlite3Tsd(); Pager *p; int nReleased = 0; int i; /* Outermost loop runs for at most two iterations. First iteration we ** try to find memory that can be released without calling fsync(). Second ** iteration (which only runs if the first failed to free nReq bytes of ** memory) is permitted to call fsync(). This is of course much more ** expensive. */ for(i=0; i==0 || i==1; i++){ /* Loop through all the SQLite pagers opened by the current thread. */ for(p=pTsd->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){ PgHdr *pPg; int rc; /* For each pager, try to free as many pages as possible (without ** calling fsync() if this is the first iteration of the outermost ** loop). */ while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) { /* We've found a page to free. At this point the page has been ** removed from the page hash-table, free-list and synced-list ** (pFirstSynced). It is still in the all pages (pAll) list. ** Remove it from this list before freeing. ** ** Todo: Check the Pager.pStmt list to make sure this is Ok. It ** probably is though. */ PgHdr *pTmp; assert( pPg ); if( pPg==p->pAll ){ p->pAll = pPg->pNextAll; }else{ for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ); pTmp->pNextAll = pPg->pNextAll; } nReleased += sqliteAllocSize(pPg); sqliteFree(pPg); } if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 | assert(0); } } } return nReleased; } /* ** Acquire a page. ** ** A read lock on the disk file is obtained when the first page is acquired. ** This read lock is dropped when the last page is released. ** | > | 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 | assert(0); } } } return nReleased; } #endif /* ** Acquire a page. ** ** A read lock on the disk file is obtained when the first page is acquired. ** This read lock is dropped when the last page is released. ** |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** ** @(#) $Id: pager.h,v 1.48 2005/12/19 14:18:11 danielk1977 Exp $ */ #ifndef _PAGER_H_ #define _PAGER_H_ /* ** The default size of a database page. |
︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | const char *sqlite3pager_dirname(Pager*); const char *sqlite3pager_journalname(Pager*); int sqlite3pager_nosync(Pager*); int sqlite3pager_rename(Pager*, const char *zNewName); void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*); int sqlite3pager_movepage(Pager*,void*,Pgno); int sqlite3pager_reset(Pager*); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3pager_lockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3pager_refdump(Pager*); int pager3_refinfo_enable; #endif #endif /* _PAGER_H_ */ | > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | const char *sqlite3pager_dirname(Pager*); const char *sqlite3pager_journalname(Pager*); int sqlite3pager_nosync(Pager*); int sqlite3pager_rename(Pager*, const char *zNewName); void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*); int sqlite3pager_movepage(Pager*,void*,Pgno); int sqlite3pager_reset(Pager*); int sqlite3pager_release_memory(int); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3pager_lockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3pager_refdump(Pager*); int pager3_refinfo_enable; #endif #endif /* _PAGER_H_ */ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** ** @(#) $Id: sqlite.h.in,v 1.150 2005/12/19 14:18:11 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 | ** For the purposes of this API, a transaction is said to have been ** rolled back if an explicit "ROLLBACK" statement is executed, or ** an error or constraint causes an implicit rollback to occur. The ** callback is not invoked if a transaction is automatically rolled ** back because the database connection is closed. */ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif | > > | 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | ** For the purposes of this API, a transaction is said to have been ** rolled back if an explicit "ROLLBACK" statement is executed, or ** an error or constraint causes an implicit rollback to occur. The ** callback is not invoked if a transaction is automatically rolled ** back because the database connection is closed. */ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); int sqlite3_release_memory(int); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.441 2005/12/19 14:18:11 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Many people are failing to set -DNDEBUG=1 when compiling SQLite. ** Setting NDEBUG makes the code smaller and run faster. So the following |
︙ | ︙ | |||
268 269 270 271 272 273 274 | /* ** An instance of this structure is allocated for each thread that uses SQLite. */ typedef struct SqliteTsd SqliteTsd; struct SqliteTsd { int isInit; /* True if structure has been initialised */ int mallocFailed; /* True after a malloc() has failed */ | < | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | /* ** An instance of this structure is allocated for each thread that uses SQLite. */ typedef struct SqliteTsd SqliteTsd; struct SqliteTsd { int isInit; /* True if structure has been initialised */ int mallocFailed; /* True after a malloc() has failed */ #ifndef SQLITE_OMIT_MEMORY_MANAGEMENT unsigned int nSoftHeapLimit; /* (uint)-1 for unlimited */ unsigned int nAlloc; /* Number of bytes currently allocated */ Pager *pPager; /* Linked list of all pagers in this thread */ #endif #ifndef NDEBUG |
︙ | ︙ |
Changes to src/tclsqlite.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite ** ** $Id: tclsqlite.c,v 1.141 2005/12/19 14:18:11 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #include "sqliteInt.h" #include "hash.h" #include "tcl.h" #include <stdlib.h> |
︙ | ︙ | |||
662 663 664 665 666 667 668 | "authorizer", "busy", "cache", "changes", "close", "collate", "collation_needed", "commit_hook", "complete", "copy", "errorcode", "eval", "exists", "function", "last_insert_rowid", "nullvalue", "onecolumn", "profile", "progress", "rekey", "rollback_hook", | | | | | | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 | "authorizer", "busy", "cache", "changes", "close", "collate", "collation_needed", "commit_hook", "complete", "copy", "errorcode", "eval", "exists", "function", "last_insert_rowid", "nullvalue", "onecolumn", "profile", "progress", "rekey", "rollback_hook", "release_memory", "soft_heap_limit", "timeout", "total_changes", "trace", "transaction", "update_hook", "version", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BUSY, DB_CACHE, DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_ROLLBACK_HOOK, DB_RELEASE_MEMORY, DB_SOFT_HEAP_LIMIT, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION, DB_UPDATE_HOOK, DB_VERSION }; /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } |
︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 | break; } /* ** $db soft_heap_limit N ** ** Set the soft-heap-limit for this thread. Note that the limit is | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 | break; } /* ** $db soft_heap_limit N ** ** Set the soft-heap-limit for this thread. Note that the limit is ** per-thread, not per-database. An empty string is returned. */ case DB_SOFT_HEAP_LIMIT: { #ifndef SQLITE_OMIT_MEMORY_MANAGEMENT int n; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "BYTES"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &n) ){ return TCL_ERROR; } sqlite3_soft_heap_limit(n); Tcl_ResetResult(interp); #endif break; } /* ** $db release_memory ?N? ** ** Try to release memory currently held (but not really required) by ** SQLite database connections opened by the current thread. If an ** integer argument is supplied, then SQLite stops trying to free memory ** after N bytes have been freed. ** ** The value returned is the number of bytes actually freed. **/ case DB_RELEASE_MEMORY: { int nRelease = 0; int N = -1; if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?N?"); return TCL_ERROR; } #ifndef SQLITE_OMIT_MEMORY_MANAGEMENT if( objc==3 && TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ return TCL_ERROR; } nRelease = sqlite3_release_memory(N); #endif Tcl_SetObjResult(interp, Tcl_NewIntObj(nRelease)); break; } /* ** $db total_changes ** ** Return the number of rows that were modified, inserted, or deleted |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** | | | > | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** ** $Id: util.c,v 1.156 2005/12/19 14:18:11 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include <stdarg.h> #include <ctype.h> /* ** MALLOC WRAPPER ARCHITECTURE ** ** The sqlite code accesses dynamic memory allocation/deallocation by invoking ** the following four APIs (which may be implemented as macros). ** ** sqlite3Malloc() ** sqlite3MallocRaw() ** sqlite3Realloc() ** sqlite3ReallocOrFree() ** sqlite3Free() ** sqlite3AllocSize() ** ** The function sqlite3FreeX performs the same task as sqlite3Free and is ** guaranteed to be a real function. The same holds for sqlite3MallocX ** ** The above APIs are implemented in terms of the functions provided at the Os ** level (not in this file). The Os level interface is never accessed directly ** by code outside of this file. ** ** sqlite3Os.xMalloc() ** sqlite3Os.xRealloc() ** sqlite3Os.xFree() ** sqlite3Os.xAllocationSize() ** ** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke ** sqlite3_release_memory() if a call to sqlite3Os.xMalloc() or ** sqlite3Os.xRealloc() fails (or if the soft-heap-limit for the thread is ** exceeded). Function sqlite3Malloc() usually invokes ** sqlite3MallocRaw(). ** ** MALLOC TEST WRAPPER ARCHITECTURE ** ** The test wrapper provides extra test facilities to ensure the library ** does not leak memory and handles the failure of the underlying (Os level) ** allocation system correctly. It is only present if the library is ** compiled with the SQLITE_MEMDEBUG macro set. ** ** * Guardposts to detect overwrites. ** * Ability to cause a specific Malloc() or Realloc() to fail. ** * Audit outstanding memory allocations (i.e check for leaks). */ #ifdef SQLITE_MEMDEBUG /*-------------------------------------------------------------------------- ** Begin code for memory allocation system test layer. ** ** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro. ** ** SQLITE_MEMDEBUG==1 -> Fence-posting only (thread safe) |
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 161 162 163 164 165 | sizeof(void *)*2 + /* pPrev and pNext pointers */ \ TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \ sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \ TESTALLOC_USERSIZE + /* User string */ \ TESTALLOC_STACKSIZE /* backtrace() stack */ \ ) /* ** For keeping track of the number of mallocs and frees. This ** is used to check for memory leaks. The iMallocFail and iMallocReset ** values are used to simulate malloc() failures during testing in ** order to verify that the library correctly handles an out-of-memory ** condition. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | sizeof(void *)*2 + /* pPrev and pNext pointers */ \ TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \ sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \ TESTALLOC_USERSIZE + /* User string */ \ TESTALLOC_STACKSIZE /* backtrace() stack */ \ ) #ifndef SQLITE_OMIT_MEMORY_MANAGEMENT /* ** Set the soft heap-size limit for the current thread. */ void sqlite3_soft_heap_limit(int n){ unsigned int N; if( n<0 ){ /* No limit */ N = 0xFFFFFFFF; }else{ N = n; } sqlite3Tsd()->nSoftHeapLimit = N; } /* ** Release memory held by SQLite instances created by the current thread. */ int sqlite3_release_memory(int n){ return sqlite3pager_release_memory(n); } #else /* If SQLITE_OMIT_MEMORY_MANAGEMENT is defined, then define a version ** of sqlite3_release_memory() to be used by other code in this file. ** This is done for no better reason than to reduce the number of ** pre-processor #ifndef statements. */ #define sqlite3_release_memory(x) 0 /* 0 == no memory freed */ #endif /* ** For keeping track of the number of mallocs and frees. This ** is used to check for memory leaks. The iMallocFail and iMallocReset ** values are used to simulate malloc() failures during testing in ** order to verify that the library correctly handles an out-of-memory ** condition. */ |
︙ | ︙ | |||
448 449 450 451 452 453 454 | void OSMALLOC_FAILED(){ sqlite3Tsd()->isFail = 0; } int OSSIZEOF(void *p){ if( p ){ | > | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | void OSMALLOC_FAILED(){ sqlite3Tsd()->isFail = 0; } int OSSIZEOF(void *p){ if( p ){ u32 *pOs = (u32 *)getOsPointer(p); return sqlite3Os.xAllocationSize(pOs) - TESTALLOC_OVERHEAD; } return 0; } #else /* Define macros to call the sqlite3Os.xXXX interface directly if ** the SQLITE_MEMDEBUG macro is not defined. |
︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 | ** Clear the "mallocFailed" flag. This should be invoked before exiting any ** entry points that may have called sqliteMalloc(). */ void sqlite3MallocClearFailed(){ sqlite3Tsd()->mallocFailed = 0; } | < < < < < < < < < < < < < < < | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | ** Clear the "mallocFailed" flag. This should be invoked before exiting any ** entry points that may have called sqliteMalloc(). */ void sqlite3MallocClearFailed(){ sqlite3Tsd()->mallocFailed = 0; } #ifndef NDEBUG /* ** This function sets a flag in the thread-specific-data structure that will ** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called. */ void sqlite3MallocDisallow(){ |
︙ | ︙ |
Added test/malloc5.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | # 2005 November 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: malloc5.test,v 1.1 2005/12/19 14:18:12 danielk1977 Exp $ #--------------------------------------------------------------------------- # NOTES ON EXPECTED BEHAVIOUR # #--------------------------------------------------------------------------- set testdir [file dirname $argv0] source $testdir/tester.tcl do_test malloc5-1.1 { # Simplest possible test. Call [db release_memory] when there is exactly # one unused page in a single pager cache. This test case set's the # value of the ::pgalloc variable, which is used in subsequent tests. # # Note: Even though executing this statement on an empty database # modifies 2 pages (the root of sqlite_master and the new root page), # the sqlite_master root (page 1) is never freed because the btree layer # retains a reference to it for the entire transaction. execsql { BEGIN; CREATE TABLE abc(a, b, c); } set ::pgalloc [db release_memory] expr $::pgalloc > 0 } {1} do_test malloc5-1.2 { # Test that the transaction started in the above test is still active. # Because the page freed had been written to, freeing it required a # journal sync and exclusive lock on the database file. Test the file # appears to be locked. sqlite3 db2 test.db catchsql { SELECT * FROM abc; } db2 } {1 {database is locked}} do_test malloc5-1.3 { # Again call [db release_memory] when there is exactly one unused page # in the cache. The same amount of memory is required, but no journal-sync # or exclusive lock should be established. execsql { COMMIT; BEGIN; SELECT * FROM abc; } db release_memory } $::pgalloc do_test malloc5-1.4 { # Database should not be locked this time. catchsql { SELECT * FROM abc; } db2 } {0 {}} do_test malloc5-1.5 { # Manipulate the cache so that it contains two unused pages. One requires # a journal-sync to free, the other does not. execsql { SELECT * FROM abc; CREATE TABLE def(d, e, f); } db release_memory 500 } $::pgalloc do_test malloc5-1.6 { # Database should not be locked this time. The above test case only # requested 500 bytes of memory, which can be obtained by freeing the page # that does not require an fsync(). catchsql { SELECT * FROM abc; } db2 } {0 {}} do_test malloc5-1.7 { # Release another 500 bytes of memory. This time we require a sync(), # so the database file will be locked afterwards. db release_memory 500 } $::pgalloc do_test malloc5-1.8 { catchsql { SELECT * FROM abc; } db2 } {1 {database is locked}} do_test malloc5-1.9 { execsql { COMMIT; } } {} do_test malloc5-2.1 { # Put some data in tables abc and def. Both tables are still wholly # contained within their root pages. execsql { INSERT INTO abc VALUES(1, 2, 3); INSERT INTO abc VALUES(4, 5, 6); INSERT INTO def VALUES(7, 8, 9); INSERT INTO def VALUES(10,11,12); } } {} do_test malloc5-2.2 { # Load the root-page for table def into the cache. Then query table abc. # Halfway through the query call sqlite3_release_memory(). The goal of this # test is to make sure we don't free pages that are in use (specifically, # the root of table abc). set nRelease 0 execsql { BEGIN; SELECT * FROM def; } db eval {SELECT * FROM abc} { incr nRelease [db release_memory] lappend data $a $b $c } list $nRelease $data } [list $pgalloc [list 1 2 3 4 5 6]] finish_test |