From 5f0961354589bc9a6241a92dc9dd4e11364d2d4d Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 28 Mar 2008 15:44:09 +0000 Subject: [PATCH] Changes to the Mem structure to reduce the frequency of freeing and reallocating the dynamic buffer. (CVS 4928) FossilOrigin-Name: d0bf73d81453da1d8e602e0445064d9f5e348063 --- manifest | 30 ++++---- manifest.uuid | 2 +- src/test_malloc.c | 4 +- src/utf.c | 3 +- src/vdbe.c | 35 ++++++---- src/vdbeInt.h | 2 + src/vdbeapi.c | 9 ++- src/vdbeaux.c | 19 +++-- src/vdbemem.c | 172 ++++++++++++++++++---------------------------- test/quick.test | 7 +- test/tester.tcl | 4 +- 11 files changed, 138 insertions(+), 149 deletions(-) diff --git a/manifest b/manifest index 8ea0cf1170..2f9e19883a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Patch\sto\sthe\snew\smemory\stracing\slogic\sthat\sallows\sit\sto\sbuild\seven\sif\nmemory\sdebugging\sis\sturned\soff.\s(CVS\s4927) -D 2008-03-28T12:53:38 +C Changes\sto\sthe\sMem\sstructure\sto\sreduce\sthe\sfrequency\sof\sfreeing\sand\sreallocating\sthe\sdynamic\sbuffer.\s(CVS\s4928) +D 2008-03-28T15:44:10 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -161,7 +161,7 @@ F src/test_devsym.c cee1aecaa90c895030399ca4ae38f84a08038f8a F src/test_func.c 9e9b33ff083b65da91c389cece903bc32de06f01 F src/test_hexio.c 1a1cd8324d57585ea86b922f609fa1fbaaf9662d F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 -F src/test_malloc.c 3be391afbfccaeaeba8a5fdb349348d2740cc9cc +F src/test_malloc.c c92a65e8f9b31bb2b332448d92d2016c000a963d F src/test_md5.c bca40b727c57462ddb415e57c5323445a1bb1a40 F src/test_onefile.c 2fea6d22f13f5f286356c80c77ffd41f995f2b7a F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f @@ -171,17 +171,17 @@ F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c 13113f94bd1c15dea9e922f08b10f3eee6863474 F src/trigger.c 9bd3b6fa0beff4a02d262c96466f752ec15a7fc3 F src/update.c 2aefd3c9277792e9fa2414dfe14202119fa49fe7 -F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4 +F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2 F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30 -F src/vdbe.c ecad5d197fe9a0f91c348fd3e776fc149aec1ae7 +F src/vdbe.c a1413f2dd70718cbea922ae58828426504b1184a F src/vdbe.h f72201a0657d5f3d6cc008d1f8d9cc65768518c9 -F src/vdbeInt.h 73a3162979585cc15d02e47cec2a1033df768246 -F src/vdbeapi.c f74189e4cae0d93b2744386b9ac57f5ab60c5133 -F src/vdbeaux.c bb810c1c5450bd7887a39d5eb44f5902e01416f8 +F src/vdbeInt.h 0b96efdeecb0803e504bf1c16b198f87c91d6019 +F src/vdbeapi.c e03b846adf7fb938b3945019dc6c4c49ed86bb0e +F src/vdbeaux.c 519ec819a8e549d087899f0c9a912afcdda762b4 F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736 -F src/vdbemem.c d48a71d66a7afd564b6537ab7e7442f7729fa5af +F src/vdbemem.c 004c5e1eb8336b22b9abfc535976026ef324ab71 F src/vtab.c 00cd16317b29495c185ff40e4b227917d5a371b2 F src/where.c 7aeeec6731dc2f423e6a77ff2964bc3c38985625 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 @@ -411,7 +411,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test c3405535b418d454e8a52196a0fc592ec9eec58d F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x F test/ptrchng.test 83150cb7b513e33cce90fdc68f4b1817551857c0 -F test/quick.test 164584ef7c350b6c439d29f248fc582d5262e71c +F test/quick.test 1ab788b4ad66cc385d06d2dd1f0714ccfb52fb61 F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0 F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b @@ -453,7 +453,7 @@ F test/table.test 13b1c2e2fb4727b35ee1fb7641fc469214fd2455 F test/tableapi.test 791f7e3891d9b70bdb43b311694bf5e9befcbc34 F test/tclsqlite.test 3fac87cb1059c46b8fa8a60b553f4f1adb0fb6d9 F test/temptable.test 19b851b9e3e64d91e9867619b2a3f5fffee6e125 -F test/tester.tcl d967b34306776a7488c3cbaf22cc4410c144ccce +F test/tester.tcl bf793fcea043ba3c0c081224bdb808efccbc8fb3 F test/thread001.test 8fbd9559da0bbdc273e00318c7fd66c162020af7 F test/thread002.test 2c4ad2c386f60f6fe268cd91c769ee35b3c1fd0b F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 @@ -619,7 +619,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P f1b97ed93183378ff56b4fe7ae8ea269c24092fc -R f8436b96b881dc0b3a43307cb3273c3d -U drh -Z bd7953b885d6238223aab5e76018f9c2 +P 0a9c63b227b9c6d2bd0e7b491245947ffc83c828 +R 4bbd70b6d864c91be4417b22dd9d1d4c +U danielk1977 +Z 85774c3fc13d70f3eca1b91a57f3702c diff --git a/manifest.uuid b/manifest.uuid index 9a1dce4ae5..a0fb5b6e0f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0a9c63b227b9c6d2bd0e7b491245947ffc83c828 \ No newline at end of file +d0bf73d81453da1d8e602e0445064d9f5e348063 \ No newline at end of file diff --git a/src/test_malloc.c b/src/test_malloc.c index 33d24bddaf..43bbfc2c96 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.21 2008/03/28 12:53:38 drh Exp $ +** $Id: test_malloc.c,v 1.22 2008/03/28 15:44:10 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -546,7 +546,7 @@ static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ } } -static int test_memdebug_log_clear(){ +static void test_memdebug_log_clear(){ Tcl_HashSearch search; Tcl_HashEntry *pEntry; for( diff --git a/src/utf.c b/src/utf.c index 3580b6dfab..da1f636d8b 100644 --- a/src/utf.c +++ b/src/utf.c @@ -12,7 +12,7 @@ ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** -** $Id: utf.c,v 1.60 2008/02/13 18:25:27 danielk1977 Exp $ +** $Id: utf.c,v 1.61 2008/03/28 15:44:10 danielk1977 Exp $ ** ** Notes on UTF-8: ** @@ -306,6 +306,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ pMem->enc = desiredEnc; pMem->flags |= (MEM_Term|MEM_Dyn); pMem->z = (char*)zOut; + pMem->zMalloc = pMem->z; translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) diff --git a/src/vdbe.c b/src/vdbe.c index 61e99978a0..5d1bb147f7 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.720 2008/03/27 22:42:52 drh Exp $ +** $Id: vdbe.c,v 1.721 2008/03/28 15:44:10 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -235,6 +235,7 @@ static Cursor *allocateCursor( */ Mem *pMem = &p->aMem[p->nMem-iCur]; + int nByte; Cursor *pCx = 0; /* If the opcode of pOp is OP_SetNumColumns, then pOp->p2 contains ** the number of fields in the records contained in the table or @@ -245,9 +246,7 @@ static Cursor *allocateCursor( if( pOp->opcode==OP_SetNumColumns || pOp->opcode==OP_OpenEphemeral ){ nField = pOp->p2; } - - - int nByte = + nByte = sizeof(Cursor) + (isBtreeCursor?sqlite3BtreeCursorSize():0) + 2*nField*sizeof(u32); @@ -668,7 +667,7 @@ int sqlite3VdbeExec( assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; - sqlite3VdbeMemRelease(pOut); + sqlite3VdbeMemReleaseExternal(pOut); pOut->flags = MEM_Null; }else @@ -880,7 +879,7 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pOut) ) goto no_mem; - pOut->flags &= ~(MEM_Dyn); + pOut->zMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3_free(pOp->p4.z); @@ -1003,7 +1002,10 @@ case OP_SCopy: { pOut = &p->aMem[pOp->p2]; assert( pOut!=pIn1 ); if( pOp->opcode==OP_Move ){ + char *zMalloc = pOut->zMalloc; + pOut->zMalloc = 0; sqlite3VdbeMemMove(pOut, pIn1); + pIn1->zMalloc = zMalloc; }else{ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); if( pOp->opcode==OP_Copy ){ @@ -1269,6 +1271,8 @@ case OP_Function: { pOut = &p->aMem[pOp->p3]; ctx.s.flags = MEM_Null; ctx.s.db = db; + ctx.s.xDel = 0; + ctx.s.zMalloc = 0; /* The output cell may already have a buffer allocated. Move ** the pointer to ctx.s so in case the user-function can use @@ -1884,6 +1888,7 @@ case OP_Column: { sMem.flags = 0; sMem.db = 0; + sMem.zMalloc = 0; assert( p1nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &p->aMem[pOp->p3]; @@ -2029,7 +2034,7 @@ case OP_Column: { aOffset[i] = 0; } } - Release(&sMem); + sqlite3VdbeMemRelease(&sMem); sMem.flags = MEM_Null; /* If we have read more header data than was contained in the header, @@ -2054,8 +2059,11 @@ case OP_Column: { if( pDest->flags&MEM_Dyn ){ sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], &sMem); sMem.db = db; - sqlite3VdbeMemCopy(pDest, &sMem); + rc = sqlite3VdbeMemCopy(pDest, &sMem); assert( !(sMem.flags&MEM_Dyn) ); + if( rc!=SQLITE_OK ){ + goto op_column_out; + } }else{ sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest); } @@ -2083,13 +2091,14 @@ case OP_Column: { ** dynamically allocated space over to the pDest structure. ** This prevents a memory copy. */ - if( (sMem.flags & MEM_Dyn)!=0 ){ - assert( !sMem.xDel ); + if( sMem.zMalloc ){ + assert( sMem.z==sMem.zMalloc ); assert( !(pDest->flags & MEM_Dyn) ); assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); pDest->flags &= ~(MEM_Ephem|MEM_Static); - pDest->flags |= MEM_Dyn|MEM_Term; + pDest->flags |= MEM_Term; pDest->z = sMem.z; + pDest->zMalloc = sMem.zMalloc; } rc = sqlite3VdbeMemMakeWriteable(pDest); @@ -3295,11 +3304,12 @@ case OP_Insert: { } pC->iKey = iKey; pC->nData = pData->n; - if( pData->flags & MEM_Dyn ){ + if( pData->z==pData->zMalloc || pC->ephemPseudoTable ){ pC->pData = pData->z; if( !pC->ephemPseudoTable ){ pData->flags &= ~MEM_Dyn; pData->flags |= MEM_Ephem; + pData->zMalloc = 0; } }else{ pC->pData = sqlite3_malloc( pC->nData+2 ); @@ -4262,6 +4272,7 @@ case OP_AggStep: { pMem->n++; ctx.s.flags = MEM_Null; ctx.s.z = 0; + ctx.s.zMalloc = 0; ctx.s.xDel = 0; ctx.s.db = db; ctx.isError = 0; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index c3a0297798..7f99daae93 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -124,6 +124,7 @@ struct Mem { u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ + char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */ }; /* One or more of the following flags are set to indicate the validOK @@ -415,6 +416,7 @@ int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); +void sqlite3VdbeMemReleaseExternal(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index c0bde8692e..32ca999674 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -614,13 +614,16 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ pMem = p->pMem; if( (pMem->flags & MEM_Agg)==0 ){ if( nByte==0 ){ - assert( pMem->flags==MEM_Null ); + sqlite3VdbeMemReleaseExternal(pMem); + pMem->flags = MEM_Null; pMem->z = 0; }else{ + sqlite3VdbeMemGrow(pMem, nByte, 0); pMem->flags = MEM_Agg; - pMem->xDel = sqlite3_free; pMem->u.pDef = p->pFunc; - pMem->z = sqlite3DbMallocZero(p->s.db, nByte); + if( pMem->z ){ + memset(pMem->z, 0, nByte); + } } } return (void*)pMem->z; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index ce37808f12..6e0b98a3cf 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -743,10 +743,12 @@ static void releaseMemArray(Mem *p, int N, int freebuffers){ int malloc_failed = db->mallocFailed; while( N-->0 ){ assert( N<2 || p[0].db==p[1].db ); - if( freebuffers || p->xDel ){ + if( freebuffers ){ sqlite3VdbeMemRelease(p); - p->flags = MEM_Null; + }else{ + sqlite3VdbeMemReleaseExternal(p); } + p->flags = MEM_Null; p++; } db->mallocFailed = malloc_failed; @@ -1030,7 +1032,6 @@ void sqlite3VdbeMakeReady( #ifdef SQLITE_DEBUG for(n=1; nnMem; n++){ assert( p->aMem[n].db==db ); - //assert( p->aMem[n].flags==MEM_Null ); } #endif @@ -1182,8 +1183,8 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){ rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT); } if( rc==SQLITE_OK && N==P4_DYNAMIC ){ - pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn; - pColName->xDel = 0; + pColName->flags &= (~MEM_Static); + pColName->zMalloc = pColName->z; } return rc; } @@ -2220,6 +2221,7 @@ UnpackedRecord *sqlite3VdbeRecordUnpack( pMem->enc = pKeyInfo->enc; pMem->db = pKeyInfo->db; pMem->flags = 0; + pMem->zMalloc = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; i++; @@ -2237,7 +2239,7 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ int i; Mem *pMem; for(i=0, pMem=p->aMem; inField; i++, pMem++){ - if( pMem->flags & MEM_Dyn ){ + if( pMem->zMalloc ){ sqlite3VdbeMemRelease(pMem); } } @@ -2285,6 +2287,7 @@ int sqlite3VdbeRecordCompare( mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = 0; + mem1.zMalloc = 0; idx1 = GetVarint(aKey1, szHdr1); d1 = szHdr1; @@ -2304,12 +2307,12 @@ int sqlite3VdbeRecordCompare( */ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], iaColl[i] : 0); - if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); if( rc!=0 ){ break; } i++; } + if( mem1.zMalloc ) sqlite3VdbeMemRelease(&mem1); /* One of the keys ran out of fields, but all the fields up to that point ** were equal. If the incrKey flag is true, then the second key is @@ -2366,6 +2369,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ } m.flags = 0; m.db = 0; + m.zMalloc = 0; rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m); if( rc ){ return rc; @@ -2409,6 +2413,7 @@ int sqlite3VdbeIdxKeyCompare( } m.db = 0; m.flags = 0; + m.zMalloc = 0; rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m); if( rc ){ return rc; diff --git a/src/vdbemem.c b/src/vdbemem.c index 8e9d061efa..1df2aff11d 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -73,50 +73,35 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ ** not set, Mem.n is zeroed. */ int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){ - int f = pMem->flags; - - assert( (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 - || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Dyn - || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Ephem - || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Static + assert( 1 >= + ((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) + + (((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) + + ((pMem->flags&MEM_Ephem) ? 1 : 0) + + ((pMem->flags&MEM_Static) ? 1 : 0) ); - if( (f&MEM_Dyn)==0 || pMem->xDel || sqlite3MallocSize(pMem->z)0 ){ - if( preserve && (f&MEM_Dyn) && !pMem->xDel ){ - z = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); - pMem->z = 0; - preserve = 0; - }else{ - z = sqlite3DbMallocRaw(pMem->db, (n>32?n:32)); - } - if( !z ){ - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Null; - return SQLITE_NOMEM; - } + if( sqlite3MallocSize(pMem->zMalloc)32?n:32); + if( preserve && pMem->z==pMem->zMalloc ){ + pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); + preserve = 0; + }else{ + sqlite3_free(pMem->zMalloc); + pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } - - /* If the value is currently a string or blob and the preserve flag - ** is true, copy the content to the new buffer. - */ - if( pMem->flags&(MEM_Blob|MEM_Str) && preserve ){ - int nCopy = (pMem->n>n?n:pMem->n); - memcpy(z, pMem->z, nCopy); - } - - /* Release the old buffer. */ - sqlite3VdbeMemRelease(pMem); - - pMem->z = z; - pMem->flags |= MEM_Dyn; - pMem->flags &= ~(MEM_Ephem|MEM_Static); - pMem->xDel = 0; } - return SQLITE_OK; + + if( preserve && pMem->z && pMem->zMalloc && pMem->z!=pMem->zMalloc ){ + memcpy(pMem->zMalloc, pMem->z, pMem->n); + } + if( pMem->xDel && pMem->flags&MEM_Dyn){ + pMem->xDel((void *)(pMem->z)); + } + + pMem->z = pMem->zMalloc; + pMem->flags &= ~(MEM_Ephem|MEM_Static); + pMem->xDel = 0; + return (pMem->z ? SQLITE_OK : SQLITE_NOMEM); } /* @@ -129,7 +114,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); expandBlob(pMem); f = pMem->flags; - if( (f&(MEM_Str|MEM_Blob)) && ((f&MEM_Dyn)==0 || pMem->xDel) ){ + if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){ if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ return SQLITE_NOMEM; } @@ -259,41 +244,47 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); ctx.s.flags = MEM_Null; ctx.s.db = pMem->db; + ctx.s.zMalloc = 0; ctx.pMem = pMem; ctx.pFunc = pFunc; ctx.isError = 0; pFunc->xFinalize(&ctx); - if( pMem->z ){ - sqlite3_free( pMem->z ); - } + assert( !pMem->xDel || 0==(pMem->flags&MEM_Dyn) ); + sqlite3_free(pMem->zMalloc); *pMem = ctx.s; rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK); } return rc; } +/* +** If the memory cell contains a string value that must be freed by +** invoking an external callback, free it now. Calling this function +** does not free any Mem.zMalloc buffer. +*/ +void sqlite3VdbeMemReleaseExternal(Mem *p){ + assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); + if( p->flags&MEM_Agg ){ + sqlite3VdbeMemFinalize(p, p->u.pDef); + assert( (p->flags & MEM_Agg)==0 ); + sqlite3VdbeMemRelease(p); + }else if( p->xDel && p->flags&MEM_Dyn ){ + p->xDel((void *)p->z); + p->xDel = 0; + } +} + /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and ** (Mem.type==SQLITE_TEXT). */ void sqlite3VdbeMemRelease(Mem *p){ - assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); - if( p->flags & (MEM_Dyn|MEM_Agg) ){ - if( p->xDel ){ - if( p->flags & MEM_Agg ){ - sqlite3VdbeMemFinalize(p, p->u.pDef); - assert( (p->flags & MEM_Agg)==0 ); - sqlite3VdbeMemRelease(p); - }else{ - p->xDel((void *)p->z); - } - }else{ - sqlite3_free(p->z); - } - p->z = 0; - p->xDel = 0; - } + sqlite3VdbeMemReleaseExternal(p); + sqlite3_free(p->zMalloc); + p->z = 0; + p->zMalloc = 0; + p->xDel = 0; } /* @@ -514,6 +505,8 @@ int sqlite3VdbeMemTooBig(Mem *p){ return 0; } +#define MEMCELLSIZE (int)(&(((Mem *)0)->zMalloc)) + /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If @@ -521,10 +514,10 @@ int sqlite3VdbeMemTooBig(Mem *p){ ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ - sqlite3VdbeMemRelease(pTo); - memcpy(pTo, pFrom, sizeof(*pFrom)); + sqlite3VdbeMemReleaseExternal(pTo); + memcpy(pTo, pFrom, MEMCELLSIZE); pTo->xDel = 0; - if( pTo->flags&MEM_Dyn ){ + if( pFrom->xDel || pFrom->z==pFrom->zMalloc ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; @@ -537,48 +530,18 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; - char *zBuf = 0; - /* If cell pTo currently has a reusable buffer, save a pointer to it - ** in local variable zBuf. This function attempts to avoid freeing - ** this buffer. - */ - if( pTo->flags&MEM_Dyn ){ - if( pTo->xDel ){ - sqlite3VdbeMemRelease(pTo); - }else{ - zBuf = pTo->z; + sqlite3VdbeMemReleaseExternal(pTo); + memcpy(pTo, pFrom, MEMCELLSIZE); + pTo->flags &= ~MEM_Dyn; + + if( pTo->flags&(MEM_Str|MEM_Blob) ){ + if( 0==(pFrom->flags&MEM_Static) ){ + pTo->flags |= MEM_Ephem; + rc = sqlite3VdbeMemMakeWriteable(pTo); } } - /* Copy the contents of *pFrom to *pTo */ - memcpy(pTo, pFrom, sizeof(*pFrom)); - - if( pTo->flags&(MEM_Str|MEM_Blob) && pTo->flags&MEM_Static ){ - /* pFrom contained a pointer to a static string. In this case, - ** free any dynamically allocated buffer associated with pTo. - */ - sqlite3_free(zBuf); - }else{ - char *zData = pTo->z; - - pTo->z = zBuf; - pTo->flags &= ~(MEM_Static|MEM_Ephem); - pTo->flags |= MEM_Dyn; - pTo->xDel = 0; - - if( pTo->flags&(MEM_Str|MEM_Blob) ){ - if( sqlite3VdbeMemGrow(pTo, pTo->n+2, 0) ){ - pTo->n = 0; - rc = SQLITE_NOMEM; - }else{ - memcpy(pTo->z, zData, pTo->n); - pTo->z[pTo->n] = '\0'; - pTo->z[pTo->n+1] = '\0'; - pTo->flags |= MEM_Term; - } - } - } return rc; } @@ -592,12 +555,12 @@ void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) ); assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) ); assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); - if( pTo->flags & MEM_Dyn ){ - sqlite3VdbeMemRelease(pTo); - } + + sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(Mem)); pFrom->flags = MEM_Null; pFrom->xDel = 0; + pFrom->zMalloc = 0; } /* @@ -659,7 +622,6 @@ int sqlite3VdbeMemSetStr( return SQLITE_NOMEM; } memcpy(pMem->z, z, nAlloc); - flags |= MEM_Dyn; }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; diff --git a/test/quick.test b/test/quick.test index 3b56748bca..c2d8ffdc9f 100644 --- a/test/quick.test +++ b/test/quick.test @@ -6,7 +6,7 @@ #*********************************************************************** # This file runs all tests. # -# $Id: quick.test,v 1.74 2008/03/27 15:07:05 drh Exp $ +# $Id: quick.test,v 1.75 2008/03/28 15:44:10 danielk1977 Exp $ proc lshift {lvar} { upvar $lvar l @@ -22,6 +22,9 @@ while {[set arg [lshift argv]] != ""} { -soak { set SOAKTEST 1 } + -start { + set STARTAT "[lshift argv]*" + } default { set argv [linsert $argv 0 $arg] break @@ -97,6 +100,8 @@ foreach testfile [lsort -dictionary [glob $testdir/*.test]] { set tail [file tail $testfile] if {[lsearch -exact $EXCLUDE $tail]>=0} continue if {[llength $INCLUDE]>0 && [lsearch -exact $INCLUDE $tail]<0} continue + if {[info exists STARTAT] && [string match $STARTAT $tail]} {unset STARTAT} + if {[info exists STARTAT]} continue source $testfile catch {db close} if {$sqlite_open_file_count>0} { diff --git a/test/tester.tcl b/test/tester.tcl index 09b86b00f0..46d39163fb 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.111 2008/03/28 07:42:54 danielk1977 Exp $ +# $Id: tester.tcl,v 1.112 2008/03/28 15:44:10 danielk1977 Exp $ set tcl_precision 15 @@ -47,7 +47,7 @@ sqlite3_soft_heap_limit $soft_limit for {set i 0} {$i<[llength $argv]} {incr i} { if {[lindex $argv $i] eq "--malloctrace"} { set argv [lreplace $argv $i $i] - sqlite3_memdebug_backtrace 5 + sqlite3_memdebug_backtrace 10 sqlite3_memdebug_log start set argv [lreplace $argv $i $i] set tester_do_malloctrace 1