Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Modify sqlite3_release_memory() to use a global LRU list of pages. Untested. (CVS 4301) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5626ce0b5e249d48b56fdc4561ef6639 |
User & Date: | danielk1977 2007-08-27 17:27:49.000 |
Context
2007-08-27
| ||
21:10 | Added the 34to35.html document describing the changes between 3.4.2 and 3.5.0. Minor interface cleanups. (CVS 4302) (check-in: 0791f917bb user: drh tags: trunk) | |
17:27 | Modify sqlite3_release_memory() to use a global LRU list of pages. Untested. (CVS 4301) (check-in: 5626ce0b5e user: danielk1977 tags: trunk) | |
2007-08-25
| ||
16:31 | Create a fresh pthread_mutexattr_t every time a recursive mutex is allocated. Ticket #2588. (CVS 4300) (check-in: 3d746343ad user: drh tags: trunk) | |
Changes
Changes to src/mutex.c.
︙ | ︙ | |||
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 file contains the C functions that implement mutexes for ** use by the SQLite core. ** | | | 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 file contains the C functions that implement mutexes for ** use by the SQLite core. ** ** $Id: mutex.c,v 1.14 2007/08/27 17:27:49 danielk1977 Exp $ */ /* ** If SQLITE_MUTEX_APPDEF is defined, then this whole module is ** omitted and equivalent functionality must be provided by the ** application that links against the SQLite library. */ #ifndef SQLITE_MUTEX_APPDEF |
︙ | ︙ | |||
249 250 251 252 253 254 255 256 257 258 259 260 261 262 | ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does | > | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
︙ | ︙ | |||
277 278 279 280 281 282 283 284 285 286 287 288 289 290 | ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ sqlite3_mutex *sqlite3_mutex_alloc(int iType){ static sqlite3_mutex staticMutexes[] = { { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, }; sqlite3_mutex *p; switch( iType ){ | > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ sqlite3_mutex *sqlite3_mutex_alloc(int iType){ static sqlite3_mutex staticMutexes[] = { { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, { PTHREAD_MUTEX_INITIALIZER, }, }; sqlite3_mutex *p; switch( iType ){ |
︙ | ︙ | |||
470 471 472 473 474 475 476 | if( p ){ p->id = iType; InitializeCriticalSection(&p->mutex); } break; } default: { | | | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | if( p ){ p->id = iType; InitializeCriticalSection(&p->mutex); } break; } default: { static sqlite3_mutex staticMutexes[5]; static int isInit = 0; while( !isInit ){ static long lock = 0; if( InterlockedIncrement(&lock)==1 ){ int i; for(i=0; i<sizeof(staticMutexes)/sizeof(staticMutexes[0]); i++){ InitializeCriticalSection(&staticMutexes[i].mutex); |
︙ | ︙ |
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.377 2007/08/27 17:27:49 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include <assert.h> #include <string.h> /* |
︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* ** This macro rounds values up so that if the value is an address it ** is guaranteed to be an address that is aligned to an 8-byte boundary. */ #define FORCE_ALIGNMENT(X) (((X)+7)&~7) /* ** Each in-memory image of a page begins with the following header. ** This header is only visible to this pager module. The client ** code that calls pager sees only the data that follows the header. ** ** Client code should call sqlite3PagerWrite() on a page prior to making ** any modifications to that page. The first time sqlite3PagerWrite() | > > > > > > > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /* ** This macro rounds values up so that if the value is an address it ** is guaranteed to be an address that is aligned to an 8-byte boundary. */ #define FORCE_ALIGNMENT(X) (((X)+7)&~7) typedef struct PgHdr PgHdr; typedef struct PagerLruLink PagerLruLink; struct PagerLruLink { PgHdr *pNext; PgHdr *pPrev; }; /* ** Each in-memory image of a page begins with the following header. ** This header is only visible to this pager module. The client ** code that calls pager sees only the data that follows the header. ** ** Client code should call sqlite3PagerWrite() on a page prior to making ** any modifications to that page. The first time sqlite3PagerWrite() |
︙ | ︙ | |||
217 218 219 220 221 222 223 | ** This flag means (when true) that the content of the page has ** not yet been loaded from disk. The in-memory content is just ** garbage. (Actually, we zero the content, but you should not ** make any assumptions about the content nevertheless.) If the ** content is needed in the future, it should be read from the ** original database file. */ | < | > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | ** This flag means (when true) that the content of the page has ** not yet been loaded from disk. The in-memory content is just ** garbage. (Actually, we zero the content, but you should not ** make any assumptions about the content nevertheless.) If the ** content is needed in the future, it should be read from the ** original database file. */ struct PgHdr { Pager *pPager; /* The pager to which this page belongs */ Pgno pgno; /* The page number for this page */ PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ PagerLruLink free; /* Next and previous free pages */ PgHdr *pNextAll; /* A list of all pages */ u8 inJournal; /* TRUE if has been written to journal */ u8 dirty; /* TRUE if we need to write back changes */ u8 needSync; /* Sync journal before writing this page */ u8 alwaysRollback; /* Disable DontRollback() for this page */ u8 needRead; /* Read content if PagerWrite() is called */ short int nRef; /* Number of users of this page */ PgHdr *pDirty, *pPrevDirty; /* Dirty pages */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT PagerLruLink gfree; /* Global list of nRef==0 pages */ #endif u32 notUsed; /* Buffer space */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; #endif /* pPager->pageSize bytes of page data follow this header */ /* Pager.nExtra bytes of local data follow the page data */ }; |
︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 | ** and back again. */ #define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) #define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) #define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize]) #define PGHDR_TO_HIST(P,PGR) \ ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) /* ** A open page cache is an instance of the following structure. ** ** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or ** or SQLITE_FULL. Once one of the first three errors occurs, it persists ** and is returned as the result of every major pager API call. The | > > > > > > > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | ** and back again. */ #define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) #define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) #define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize]) #define PGHDR_TO_HIST(P,PGR) \ ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) typedef struct PagerLruList PagerLruList; struct PagerLruList { PgHdr *pFirst; PgHdr *pLast; PgHdr *pFirstSynced; /* First page in list with PgHdr.needSync==0 */ }; /* ** A open page cache is an instance of the following structure. ** ** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or ** or SQLITE_FULL. Once one of the first three errors occurs, it persists ** and is returned as the result of every major pager API call. The |
︙ | ︙ | |||
334 335 336 337 338 339 340 | u8 *aInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ sqlite3_file *fd, *jfd; /* File descriptors for database and journal */ sqlite3_file *stfd; /* File descriptor for the statement subjournal*/ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ | | < | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | u8 *aInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ sqlite3_file *fd, *jfd; /* File descriptors for database and journal */ sqlite3_file *stfd; /* File descriptor for the statement subjournal*/ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PagerLruList lru; /* LRU list of free pages */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ PgHdr *pDirty; /* List of all dirty pages */ i64 journalOff; /* Current byte offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ i64 stmtHdrOff; /* First journal header written this statement */ i64 stmtCksum; /* cksumInit when statement was started */ |
︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 | ** The following variable points to the head of a double-linked list ** of all pagers that are eligible for page stealing by the ** sqlite3_release_memory() interface. Access to this list is ** protected by the SQLITE_MUTEX_STATIC_MEM2 mutex. */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT static Pager *sqlite3PagerList = 0; #endif /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. ** | > | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | ** The following variable points to the head of a double-linked list ** of all pagers that are eligible for page stealing by the ** sqlite3_release_memory() interface. Access to this list is ** protected by the SQLITE_MUTEX_STATIC_MEM2 mutex. */ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT static Pager *sqlite3PagerList = 0; static PagerLruList sqlite3LruPageList = {0, 0, 0}; #endif /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. ** |
︙ | ︙ | |||
510 511 512 513 514 515 516 517 518 519 520 521 522 523 | ); cnt++; /* Something to set a breakpoint on */ } # define REFINFO(X) pager_refinfo(X) #else # define REFINFO(X) #endif /* ** Return true if page *pPg has already been written to the statement ** journal (or statement snapshot has been created, if *pPg is part ** of an in-memory database). */ static int pageInStatement(PgHdr *pPg){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | ); cnt++; /* Something to set a breakpoint on */ } # define REFINFO(X) pager_refinfo(X) #else # define REFINFO(X) #endif static void listAdd(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ pLink->pNext = 0; pLink->pPrev = pList->pLast; if( pList->pLast ){ int iOff = (char *)pLink - (char *)pPg; PagerLruLink *pLastLink = (PagerLruLink *)(&((u8 *)pList->pLast)[iOff]); pLastLink->pNext = pPg; }else{ assert(!pList->pFirst); pList->pFirst = pPg; } pList->pLast = pPg; if( !pList->pFirstSynced && pPg->needSync==0 ){ pList->pFirstSynced = pPg; } } static void listRemove(PagerLruList *pList, PagerLruLink *pLink, PgHdr *pPg){ int iOff = (char *)pLink - (char *)pPg; if( pPg==pList->pFirst ){ pList->pFirst = pLink->pNext; } if( pPg==pList->pLast ){ pList->pLast = pLink->pPrev; } if( pLink->pPrev ){ PagerLruLink *pPrevLink = (PagerLruLink *)(&((u8 *)pLink->pPrev)[iOff]); pPrevLink->pNext = pLink->pNext; } if( pLink->pNext ){ PagerLruLink *pNextLink = (PagerLruLink *)(&((u8 *)pLink->pNext)[iOff]); pNextLink->pPrev = pLink->pPrev; } if( pPg==pList->pFirstSynced ){ PgHdr *p = pLink->pNext; while( p && p->needSync ){ PagerLruLink *pL = (PagerLruLink *)(&((u8 *)p)[iOff]); p = pL->pNext; } pList->pFirstSynced = p; } pLink->pNext = pLink->pPrev = 0; } /* ** Add page to the free-list */ static void lruListAdd(PgHdr *pPg){ listAdd(&pPg->pPager->lru, &pPg->free, pPg); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( !pPg->pPager->memDb ){ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); listAdd(&sqlite3LruPageList, &pPg->gfree, pPg); sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); } #endif } /* ** Remove page from free-list */ static void lruListRemove(PgHdr *pPg){ listRemove(&pPg->pPager->lru, &pPg->free, pPg); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( !pPg->pPager->memDb ){ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); listRemove(&sqlite3LruPageList, &pPg->gfree, pPg); sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); } #endif } /* ** Set the Pager.pFirstSynced variable */ static void lruListSetFirstSynced(Pager *pPager){ pPager->lru.pFirstSynced = pPager->lru.pFirst; #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( !pPager->memDb ){ PgHdr *p; sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); for(p=sqlite3LruPageList.pFirst; p && p->needSync; p=p->gfree.pNext); assert(p==pPager->lru.pFirstSynced || p==sqlite3LruPageList.pFirstSynced); sqlite3LruPageList.pFirstSynced = p; sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); } #endif } /* ** Return true if page *pPg has already been written to the statement ** journal (or statement snapshot has been created, if *pPg is part ** of an in-memory database). */ static int pageInStatement(PgHdr *pPg){ |
︙ | ︙ | |||
1077 1078 1079 1080 1081 1082 1083 1084 1085 | static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; if( pPager->errCode ) return; for(pPg=pPager->pAll; pPg; pPg=pNext){ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; sqlite3_free(pPg); } | > | | | | | 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | static void pager_reset(Pager *pPager){ PgHdr *pPg, *pNext; if( pPager->errCode ) return; for(pPg=pPager->pAll; pPg; pPg=pNext){ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; lruListRemove(pPg); sqlite3_free(pPg); } assert(pPager->lru.pFirst==0); assert(pPager->lru.pFirstSynced==0); assert(pPager->lru.pLast==0); pPager->pStmt = 0; pPager->pAll = 0; pPager->nHash = 0; sqlite3_free(pPager->aHash); pPager->nPage = 0; pPager->aHash = 0; pPager->nRef = 0; } |
︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; } pPager->origDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; | | | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 | pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; } pPager->origDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; lruListSetFirstSynced(pPager); pPager->dbSize = -1; return (rc==SQLITE_OK?rc2:rc); } /* ** Compute and return a checksum for the page of data. |
︙ | ︙ | |||
2280 2281 2282 2283 2284 2285 2286 | /* ** Unlink a page from the free list (the list of all pages where nRef==0) ** and from its hash collision chain. */ static void unlinkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; | < < < < < < < | | < < < < < < < < < < < < | 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 | /* ** Unlink a page from the free list (the list of all pages where nRef==0) ** and from its hash collision chain. */ static void unlinkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Unlink from free page list */ lruListRemove(pPg); /* Unlink from the pgno hash table */ unlinkHashChain(pPager, pPg); } /* ** This routine is used to truncate the cache when a database |
︙ | ︙ | |||
2494 2495 2496 2497 2498 2499 2500 | ** For non-test systems, page_ref() is a macro that calls _page_ref() ** online of the reference count is zero. For test systems, page_ref() ** is a real function so that we can set breakpoints and trace it. */ static void _page_ref(PgHdr *pPg){ if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ | < < < < < | < < < < < < < < < | 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 | ** For non-test systems, page_ref() is a macro that calls _page_ref() ** online of the reference count is zero. For test systems, page_ref() ** is a real function so that we can set breakpoints and trace it. */ static void _page_ref(PgHdr *pPg){ if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ lruListRemove(pPg); pPg->pPager->nRef++; } pPg->nRef++; REFINFO(pPg); } #ifdef SQLITE_DEBUG static void page_ref(PgHdr *pPg){ |
︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 | pPager->needSync = 0; /* Erase the needSync flag from every page. */ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->needSync = 0; } | | | | 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 | pPager->needSync = 0; /* Erase the needSync flag from every page. */ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->needSync = 0; } lruListSetFirstSynced(pPager); } #ifndef NDEBUG /* If the Pager.needSync flag is clear then the PgHdr.needSync ** flag must also be clear for all pages. Verify that this ** invariant is true. */ else{ for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); } #endif return rc; } /* |
︙ | ︙ | |||
2853 2854 2855 2856 2857 2858 2859 | *ppPg = 0; assert(!MEMDB); /* Find a page to recycle. Try to locate a page that does not ** require us to do an fsync() on the journal. */ | | | | | 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 | *ppPg = 0; assert(!MEMDB); /* Find a page to recycle. Try to locate a page that does not ** require us to do an fsync() on the journal. */ pPg = pPager->lru.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->lru.pFirst && syncOk && !MEMDB){ int iDc = sqlite3OsDeviceCharacteristics(pPager->fd); int rc = syncJournal(pPager); if( rc!=0 ){ return rc; } if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){ /* If in full-sync mode, write a new journal header into the ** journal file. This is done to avoid ever modifying a journal ** header that is involved in the rollback of pages that have ** already been written to the database (in case the header is ** trashed when the nRec field is updated). */ pPager->nRec = 0; assert( pPager->journalOff > 0 ); assert( pPager->doNotSync==0 ); rc = writeJournalHdr(pPager); if( rc!=0 ){ return rc; } } pPg = pPager->lru.pFirst; } if( pPg==0 ){ return SQLITE_OK; } assert( pPg->nRef==0 ); |
︙ | ︙ | |||
2941 2942 2943 2944 2945 2946 2947 | ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ int sqlite3PagerReleaseMemory(int nReq){ int nReleased = 0; /* Bytes of memory released so far */ sqlite3_mutex *mutex; /* The MEM2 mutex */ Pager *pPager; /* For looping over pagers */ | | > > > | | < | < | < > > > > | < > | | | < | < < | > | | < < | > > | < | | < > | | | | | | | | | | | | | | | | | | | | | | | | | < < | | | | | | | | | | | | | < | 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 | ** been released, the function returns. The return value is the total number ** of bytes of memory released. */ int sqlite3PagerReleaseMemory(int nReq){ int nReleased = 0; /* Bytes of memory released so far */ sqlite3_mutex *mutex; /* The MEM2 mutex */ Pager *pPager; /* For looping over pagers */ int rc = SQLITE_OK; /* Acquire the memory-management mutex */ mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2); sqlite3_mutex_enter(mutex); /* Signal all database connections that memory management wants ** to have access to the pagers. */ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ pPager->iInUseMM = 1; } while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){ PgHdr *pPg; PgHdr *pRecycled; /* Try to find a page to recycle that does not require a sync(). If ** this is not possible, find one that does require a sync(). */ sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); pPg = sqlite3LruPageList.pFirstSynced; while( pPg && (pPg->needSync || pPg->pPager->iInUseDB) ){ pPg = pPg->gfree.pNext; } if( !pPg ){ pPg = sqlite3LruPageList.pFirst; while( pPg && pPg->pPager->iInUseDB ){ pPg = pPg->gfree.pNext; } } sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU)); if( !pPg ) break; pPager = pPg->pPager; assert(!pPg->needSync || pPg==pPager->lru.pFirst); assert(pPg->needSync || pPg==pPager->lru.pFirstSynced); rc = pager_recycle(pPager, 1, &pRecycled); assert(pRecycled==pPg || rc!=SQLITE_OK); if( rc==SQLITE_OK ){ /* 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==pPager->pAll ){ pPager->pAll = pPg->pNextAll; }else{ for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){} pTmp->pNextAll = pPg->pNextAll; } nReleased += ( sizeof(*pPg) + pPager->pageSize + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); sqlite3_free(pPg); }else{ /* An error occured whilst writing to the database file or ** journal in pager_recycle(). The error is not returned to the ** caller of this function. Instead, set the Pager.errCode variable. ** The error will be returned to the user (or users, in the case ** of a shared pager cache) of the pager for which the error occured. */ assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL || rc==SQLITE_BUSY ); assert( pPager->state>=PAGER_RESERVED ); pager_error(pPager, rc); } } /* Clear the memory management flags and release the mutex */ for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){ pPager->iInUseMM = 0; |
︙ | ︙ | |||
3248 3249 3250 3251 3252 3253 3254 | static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; /* Create a new PgHdr if any of the four conditions defined ** above are met: */ if( pPager->nPage<pPager->mxPage | | | | 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 | static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; /* Create a new PgHdr if any of the four conditions defined ** above are met: */ if( pPager->nPage<pPager->mxPage || pPager->lru.pFirst==0 || MEMDB || (pPager->lru.pFirstSynced==0 && pPager->doNotSync) ){ if( pPager->nPage>=pPager->nHash ){ pager_resize_hash_table(pPager, pPager->nHash<256 ? 256 : pPager->nHash*2); if( pPager->nHash==0 ){ rc = SQLITE_NOMEM; goto pager_allocate_out; |
︙ | ︙ | |||
3537 3538 3539 3540 3541 3542 3543 | CHECK_PAGE(pPg); /* When the number of references to a page reach 0, call the ** destructor and add the page to the freelist. */ if( pPg->nRef==0 ){ | | < < < < < < < < | < | < | 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 | CHECK_PAGE(pPg); /* When the number of references to a page reach 0, call the ** destructor and add the page to the freelist. */ if( pPg->nRef==0 ){ Pager *pPager = pPg->pPager; lruListAdd(pPg); if( pPager->xDestructor ){ pPager->xDestructor(pPg, pPager->pageSize); } /* When all pages reach the freelist, drop the read lock from ** the database file. */ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** ** @(#) $Id: sqlite.h.in,v 1.243 2007/08/27 17:27:49 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++. |
︙ | ︙ | |||
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 | ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does | > | 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 | ** <ul> ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
︙ | ︙ | |||
3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 | */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 #define SQLITE_MUTEX_STATIC_MASTER 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT | > | 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 | */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 #define SQLITE_MUTEX_STATIC_MASTER 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT |
︙ | ︙ |