Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | When possible, reuse file-descriptors from the deferred-close list instead of opening new ones. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
93504574141264393155f0e09ff0b092 |
User & Date: | dan 2012-09-05 16:18:49.886 |
Context
2012-09-05
| ||
17:15 | Fix a problem in test script misuse.test. check-in: 0ed91ba599 user: dan tags: trunk | |
16:18 | When possible, reuse file-descriptors from the deferred-close list instead of opening new ones. check-in: 9350457414 user: dan tags: trunk | |
11:38 | Fix some test script bugs in src4.test. check-in: 132d76341e user: dan tags: trunk | |
Changes
Changes to src/lsmInt.h.
︙ | ︙ | |||
620 621 622 623 624 625 626 627 628 629 630 631 632 633 | /* Functions to read, write and sync the log file. */ int lsmFsWriteLog(FileSystem *pFS, i64 iOff, LsmString *pStr); int lsmFsSyncLog(FileSystem *pFS); int lsmFsReadLog(FileSystem *pFS, i64 iOff, int nRead, LsmString *pStr); int lsmFsTruncateLog(FileSystem *pFS, i64 nByte); int lsmFsCloseAndDeleteLog(FileSystem *pFS); /* And to sync the db file */ int lsmFsSyncDb(FileSystem *); /* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */ int lsmInfoArrayStructure(lsm_db *pDb, Pgno iFirst, char **pzOut); int lsmConfigMmap(lsm_db *pDb, int *piParam); | > > | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | /* Functions to read, write and sync the log file. */ int lsmFsWriteLog(FileSystem *pFS, i64 iOff, LsmString *pStr); int lsmFsSyncLog(FileSystem *pFS); int lsmFsReadLog(FileSystem *pFS, i64 iOff, int nRead, LsmString *pStr); int lsmFsTruncateLog(FileSystem *pFS, i64 nByte); int lsmFsCloseAndDeleteLog(FileSystem *pFS); void lsmFsDeferClose(FileSystem *pFS, LsmFile **pp); /* And to sync the db file */ int lsmFsSyncDb(FileSystem *); /* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */ int lsmInfoArrayStructure(lsm_db *pDb, Pgno iFirst, char **pzOut); int lsmConfigMmap(lsm_db *pDb, int *piParam); |
︙ | ︙ | |||
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | int lsmLsmInUse(lsm_db *db, i64 iLsmId, int *pbInUse); int lsmTreeInUse(lsm_db *db, u32 iLsmId, int *pbInUse); int lsmFreelistAppend(lsm_env *pEnv, Freelist *p, int iBlk, i64 iId); int lsmDbMultiProc(lsm_db *); void lsmDbDeferredClose(lsm_db *, lsm_file *, LsmFile *); /************************************************************************** ** functions in lsm_str.c */ void lsmStringInit(LsmString*, lsm_env *pEnv); int lsmStringExtend(LsmString*, int); int lsmStringAppend(LsmString*, const char *, int); void lsmStringVAppendf(LsmString*, const char *zFormat, va_list, va_list); void lsmStringAppendf(LsmString*, const char *zFormat, ...); void lsmStringClear(LsmString*); char *lsmMallocPrintf(lsm_env*, const char*, ...); int lsmStringBinAppend(LsmString *pStr, const u8 *a, int n); /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ #define ROUND8(x) (((x)+7)&~7) #define LSM_MIN(x,y) ((x)>(y) ? (y) : (x)) #define LSM_MAX(x,y) ((x)>(y) ? (x) : (y)) #endif | > > > | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 | int lsmLsmInUse(lsm_db *db, i64 iLsmId, int *pbInUse); int lsmTreeInUse(lsm_db *db, u32 iLsmId, int *pbInUse); int lsmFreelistAppend(lsm_env *pEnv, Freelist *p, int iBlk, i64 iId); int lsmDbMultiProc(lsm_db *); void lsmDbDeferredClose(lsm_db *, lsm_file *, LsmFile *); LsmFile *lsmDbRecycleFd(lsm_db *); /************************************************************************** ** functions in lsm_str.c */ void lsmStringInit(LsmString*, lsm_env *pEnv); int lsmStringExtend(LsmString*, int); int lsmStringAppend(LsmString*, const char *, int); void lsmStringVAppendf(LsmString*, const char *zFormat, va_list, va_list); void lsmStringAppendf(LsmString*, const char *zFormat, ...); void lsmStringClear(LsmString*); char *lsmMallocPrintf(lsm_env*, const char*, ...); int lsmStringBinAppend(LsmString *pStr, const u8 *a, int n); int lsmStrlen(const char *zName); /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ #define ROUND8(x) (((x)+7)&~7) #define LSM_MIN(x,y) ((x)>(y) ? (y) : (x)) #define LSM_MAX(x,y) ((x)>(y) ? (x) : (y)) #endif |
Changes to src/lsm_file.c.
︙ | ︙ | |||
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | assert( pDb->pFS==0 ); assert( pDb->pWorker==0 && pDb->pClient==0 ); nByte = sizeof(FileSystem) + nDb+1 + nDb+4+1; pFS = (FileSystem *)lsmMallocZeroRc(pDb->pEnv, nByte, &rc); if( pFS ){ pFS->zDb = (char *)&pFS[1]; pFS->zLog = &pFS->zDb[nDb+1]; pFS->nPagesize = LSM_PAGE_SIZE; pFS->nBlocksize = LSM_BLOCK_SIZE; pFS->nMetasize = 4 * 1024; pFS->pDb = pDb; pFS->pEnv = pDb->pEnv; /* Make a copy of the database and log file names. */ memcpy(pFS->zDb, zDb, nDb+1); memcpy(pFS->zLog, zDb, nDb); memcpy(&pFS->zLog[nDb], "-log", 5); /* Allocate the hash-table here. At some point, it should be changed ** so that it can grow dynamicly. */ pFS->nCacheMax = 2048; pFS->nHash = 4096; pFS->apHash = lsmMallocZeroRc(pDb->pEnv, sizeof(Page *) * pFS->nHash, &rc); | > < > > > > > > > > | > > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | assert( pDb->pFS==0 ); assert( pDb->pWorker==0 && pDb->pClient==0 ); nByte = sizeof(FileSystem) + nDb+1 + nDb+4+1; pFS = (FileSystem *)lsmMallocZeroRc(pDb->pEnv, nByte, &rc); if( pFS ){ LsmFile *pLsmFile; pFS->zDb = (char *)&pFS[1]; pFS->zLog = &pFS->zDb[nDb+1]; pFS->nPagesize = LSM_PAGE_SIZE; pFS->nBlocksize = LSM_BLOCK_SIZE; pFS->nMetasize = 4 * 1024; pFS->pDb = pDb; pFS->pEnv = pDb->pEnv; /* Make a copy of the database and log file names. */ memcpy(pFS->zDb, zDb, nDb+1); memcpy(pFS->zLog, zDb, nDb); memcpy(&pFS->zLog[nDb], "-log", 5); /* Allocate the hash-table here. At some point, it should be changed ** so that it can grow dynamicly. */ pFS->nCacheMax = 2048; pFS->nHash = 4096; pFS->apHash = lsmMallocZeroRc(pDb->pEnv, sizeof(Page *) * pFS->nHash, &rc); /* Open the database file */ pLsmFile = lsmDbRecycleFd(pDb); if( pLsmFile ){ pFS->pLsmFile = pLsmFile; pFS->fdDb = pLsmFile->pFile; memset(pLsmFile, 0, sizeof(LsmFile)); }else{ pFS->pLsmFile = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmFile), &rc); if( rc==LSM_OK ){ pFS->fdDb = fsOpenFile(pFS, 0, &rc); } } if( rc!=LSM_OK ){ lsmFsClose(pFS); pFS = 0; } } |
︙ | ︙ | |||
428 429 430 431 432 433 434 | Page *pNext = pPg->pLruNext; if( pPg->flags & PAGE_FREE ) lsmFree(pEnv, pPg->aData); lsmFree(pEnv, pPg); pPg = pNext; } if( pFS->fdDb ) lsmEnvClose(pFS->pEnv, pFS->fdDb ); | < < < < < | < < < > > > > > > > > > | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | Page *pNext = pPg->pLruNext; if( pPg->flags & PAGE_FREE ) lsmFree(pEnv, pPg->aData); lsmFree(pEnv, pPg); pPg = pNext; } if( pFS->fdDb ) lsmEnvClose(pFS->pEnv, pFS->fdDb ); if( pFS->fdLog ) lsmEnvClose(pFS->pEnv, pFS->fdLog ); lsmFree(pEnv, pFS->pLsmFile); lsmFree(pEnv, pFS->apHash); lsmFree(pEnv, pFS); } } void lsmFsDeferClose(FileSystem *pFS, LsmFile **pp){ LsmFile *p = pFS->pLsmFile; assert( p->pNext==0 ); p->pFile = pFS->fdDb; pFS->fdDb = 0; pFS->pLsmFile = 0; *pp = p; } /* ** Allocate a buffer and populate it with the output of the xFileid() ** method of the database file handle. If successful, set *ppId to point ** to the buffer and *pnId to the number of bytes in the buffer and return ** LSM_OK. Otherwise, set *ppId and *pnId to zero and return an LSM ** error code. |
︙ | ︙ |
Changes to src/lsm_main.c.
︙ | ︙ | |||
169 170 171 172 173 174 175 | ** than one purpose - to open both the database and log files, and ** perhaps to unlink the log file during disconnection. An absolute ** path is required to ensure that the correct files are operated ** on even if the application changes the cwd. */ rc = getFullpathname(pDb->pEnv, zFilename, &zFull); assert( rc==LSM_OK || zFull==0 ); | < < < < < | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | ** than one purpose - to open both the database and log files, and ** perhaps to unlink the log file during disconnection. An absolute ** path is required to ensure that the correct files are operated ** on even if the application changes the cwd. */ rc = getFullpathname(pDb->pEnv, zFilename, &zFull); assert( rc==LSM_OK || zFull==0 ); /* Connect to the database */ if( rc==LSM_OK ){ rc = lsmDbDatabaseConnect(pDb, zFull); } /* Configure the file-system connection with the page-size and block-size ** of this database. Even if the database file is zero bytes in size ** on disk, these values have been set in shared-memory by now, and so are ** guaranteed not to change during the lifetime of this connection. */ if( rc==LSM_OK && LSM_OK==(rc = lsmCheckpointLoad(pDb)) ){ |
︙ | ︙ |
Changes to src/lsm_shared.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 | ** list starting at global variable gShared.pDatabase. Database objects are ** reference counted. Once the number of connections to the associated ** database drops to zero, they are removed from the linked list and deleted. */ struct Database { /* Protected by the global mutex (enterGlobalMutex/leaveGlobalMutex): */ char *zName; /* Canonical path to database file */ | | < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | ** list starting at global variable gShared.pDatabase. Database objects are ** reference counted. Once the number of connections to the associated ** database drops to zero, they are removed from the linked list and deleted. */ struct Database { /* Protected by the global mutex (enterGlobalMutex/leaveGlobalMutex): */ char *zName; /* Canonical path to database file */ int nName; /* strlen(zName) */ int nDbRef; /* Number of associated lsm_db handles */ Database *pDbNext; /* Next Database structure in global list */ /* Protected by the local mutex (pClientMutex) */ lsm_file *pFile; /* Used for locks/shm in multi-proc mode */ LsmFile *pLsmFile; /* List of deferred closes */ lsm_mutex *pClientMutex; /* Protects the apShmChunk[] and pConn */ |
︙ | ︙ | |||
254 255 256 257 258 259 260 | ** and and LSM error code returned. ** ** Each successful call to this function should be (eventually) matched ** by a call to lsmDbDatabaseRelease(). */ int lsmDbDatabaseConnect( lsm_db *pDb, /* Database handle */ | | | < < < < | < | < < | | < < < < < > < < < < < | | > | > > > > | > < > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | ** and and LSM error code returned. ** ** Each successful call to this function should be (eventually) matched ** by a call to lsmDbDatabaseRelease(). */ int lsmDbDatabaseConnect( lsm_db *pDb, /* Database handle */ const char *zName /* Full-path to db file */ ){ lsm_env *pEnv = pDb->pEnv; int rc; /* Return code */ Database *p = 0; /* Pointer returned via *ppDatabase */ int nName = lsmStrlen(zName); assert( pDb->pDatabase==0 ); rc = enterGlobalMutex(pEnv); if( rc==LSM_OK ){ /* Search the global list for an existing object. TODO: Need something ** better than the strcmp() below to figure out if a given Database ** object represents the requested file. */ for(p=gShared.pDatabase; p; p=p->pDbNext){ if( nName==p->nName && 0==memcmp(zName, p->zName, nName) ) break; } /* If no suitable Database object was found, allocate a new one. */ if( p==0 ){ p = (Database *)lsmMallocZeroRc(pEnv, sizeof(Database)+nName+1, &rc); /* If the allocation was successful, fill in other fields and ** allocate the client mutex. */ if( rc==LSM_OK ){ p->zName = (char *)&p[1]; p->nName = nName; memcpy((void *)p->zName, zName, nName+1); rc = lsmMutexNew(pEnv, &p->pClientMutex); } /* If running in multi-process mode and nothing has gone wrong so far, ** open the shared fd */ if( rc==LSM_OK && pDb->bMultiProc ){ rc = lsmEnvOpen(pDb->pEnv, p->zName, &p->pFile); } if( rc==LSM_OK ){ p->pDbNext = gShared.pDatabase; gShared.pDatabase = p; }else{ freeDatabase(pEnv, p); p = 0; } } if( p ){ p->nDbRef++; } leaveGlobalMutex(pEnv); if( p ){ lsmMutexEnter(pDb->pEnv, p->pClientMutex); pDb->pNext = p->pConn; p->pConn = pDb; lsmMutexLeave(pDb->pEnv, p->pClientMutex); } } pDb->pDatabase = p; if( rc==LSM_OK ){ assert( p ); rc = lsmFsOpen(pDb, zName); } if( rc==LSM_OK ){ rc = doDbConnect(pDb); } return rc; } static void dbDeferClose(lsm_db *pDb){ if( pDb->pFS ){ LsmFile *pLsmFile = 0; Database *p = pDb->pDatabase; lsmFsDeferClose(pDb->pFS, &pLsmFile); pLsmFile->pNext = p->pLsmFile; p->pLsmFile = pLsmFile; } } LsmFile *lsmDbRecycleFd(lsm_db *db){ LsmFile *pRet; Database *p = db->pDatabase; lsmMutexEnter(db->pEnv, p->pClientMutex); if( pRet = p->pLsmFile ){ p->pLsmFile = pRet->pNext; } lsmMutexLeave(db->pEnv, p->pClientMutex); return pRet; } /* ** Release a reference to a Database object obtained from ** lsmDbDatabaseConnect(). There should be exactly one call to this function ** for each successful call to Find(). */ void lsmDbDatabaseRelease(lsm_db *pDb){ Database *p = pDb->pDatabase; if( p ){ lsm_db **ppDb; if( pDb->pShmhdr ){ doDbDisconnect(pDb); } lsmMutexEnter(pDb->pEnv, p->pClientMutex); for(ppDb=&p->pConn; *ppDb!=pDb; ppDb=&((*ppDb)->pNext)); *ppDb = pDb->pNext; if( lsmDbMultiProc(pDb) ){ dbDeferClose(pDb); } lsmMutexLeave(pDb->pEnv, p->pClientMutex); enterGlobalMutex(pDb->pEnv); p->nDbRef--; if( p->nDbRef==0 ){ Database **pp; |
︙ | ︙ | |||
885 886 887 888 889 890 891 | ** lsmDbDatabaseConnect(). It returns true if the connection is in ** multi-process mode, or false otherwise. */ int lsmDbMultiProc(lsm_db *pDb){ return pDb->pDatabase && (pDb->pDatabase->pFile!=0); } | < < < < < < < < < < < | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 | ** lsmDbDatabaseConnect(). It returns true if the connection is in ** multi-process mode, or false otherwise. */ int lsmDbMultiProc(lsm_db *pDb){ return pDb->pDatabase && (pDb->pDatabase->pFile!=0); } /************************************************************************* ************************************************************************** ************************************************************************** ************************************************************************** ************************************************************************** *************************************************************************/ |
︙ | ︙ |
Changes to src/lsm_str.c.
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 131 132 133 134 135 | va_list ap, ap2; va_start(ap, zFormat); va_start(ap2, zFormat); lsmStringVAppendf(pStr, zFormat, ap, ap2); va_end(ap); va_end(ap2); } /* ** Write into memory obtained from lsm_malloc(). */ char *lsmMallocPrintf(lsm_env *pEnv, const char *zFormat, ...){ LsmString s; va_list ap, ap2; | > > > > > > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | va_list ap, ap2; va_start(ap, zFormat); va_start(ap2, zFormat); lsmStringVAppendf(pStr, zFormat, ap, ap2); va_end(ap); va_end(ap2); } int lsmStrlen(const char *zName){ int nRet = 0; while( zName[nRet] ) nRet++; return nRet; } /* ** Write into memory obtained from lsm_malloc(). */ char *lsmMallocPrintf(lsm_env *pEnv, const char *zFormat, ...){ LsmString s; va_list ap, ap2; |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
129 130 131 132 133 134 135 | # quick # full # lappend ::testsuitelist xxx test_suite "src4" -prefix "" -description { } -files { | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | # quick # full # lappend ::testsuitelist xxx test_suite "src4" -prefix "" -description { } -files { simple.test simple2.test log1.test log2.test log3.test csr1.test ckpt1.test aggerror.test attach.test autoindex1.test |
︙ | ︙ |
Added test/simple2.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 | # 2012 September 05 # # 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. # #*********************************************************************** # The tests in this file were used while developing the SQLite 4 code. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix simple2 db_delete test2.db do_execsql_test 1.1 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES('abc', 'def'); ATTACH 'test2.db' AS aux; CREATE TABLE aux.t1 AS SELECT * FROM main.t1; DETACH aux; } do_test 1.2 { set nIncorrect 0 for {set i 0} {$i < 2000} {incr i} { sqlite4 db2 test2.db set res [execsql {SELECT * FROM t1} db2] incr nIncorrect [string compare "abc def" $res] db2 close } set nIncorrect } {0} do_test 1.3 { set nIncorrect 0 for {set i 0} {$i < 2000} {incr i} { sqlite4 db2 test.db set res [execsql {SELECT * FROM t1} db2] incr nIncorrect [string compare "abc def" $res] db2 close } set nIncorrect } {0} do_test 1.4 { set nIncorrect 0 set res [list [catch { for {set i 2} {$i < 2000} {incr i} { sqlite4 db$i test.db set res [execsql {SELECT * FROM t1} db$i] incr nIncorrect [string compare "abc def" $res] } } msg] $msg] set res } {1 {disk I/O error}} do_test 1.5 { for {set i 2} {$i < 2000} {incr i} { catch {db$i close} } set res {} } {} finish_test |