fix a memory leak in btree_rb.c. (CVS 918)

FossilOrigin-Name: 1e3d0d094776c2a429fa2a3eebc036a0b6374862
This commit is contained in:
drh 2003-04-18 22:52:38 +00:00
parent cab20050bb
commit 9d10f1d0f6
3 changed files with 206 additions and 209 deletions

View File

@ -1,5 +1,5 @@
C Fix\sfor\sticket\s#297\s-\sbug\sin\ssqliteSortCompare().\s(CVS\s917)
D 2003-04-18T17:45:14
C fix\sa\smemory\sleak\sin\sbtree_rb.c.\s(CVS\s918)
D 2003-04-18T22:52:39
F Makefile.in df3a4db41a7450468b5fe934d9dd8f723b631249
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -23,7 +23,7 @@ F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
F src/auth.c 2dd558dba4d8ffbed25fe1644e9af242f389f3e9
F src/btree.c b9487cceb9ea78af9cbae9def34114902f511736
F src/btree.h 529c98cb0715c62214544fbbe50b946f99a85540
F src/btree_rb.c 7fa4901a65de66522ce31985833f20b98f7baad4
F src/btree_rb.c b14803c84dc1c8fb51f5db1542237b7b7d411957
F src/build.c 6694013c86c4c480754f515ddab561302c6e732a
F src/copy.c 8699e571994934c78f70761a1458d7b9e9e75073
F src/delete.c af65b26d9d13abbf63fdc4e97b88d26c700b04bb
@ -162,7 +162,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 6e948d9aaea109c683ac4fcc4714e335b545d22b
R d350172ce34cbf799885ede2eb5043c7
P 4ded1965eb83dee0f28c27ba935d615c77331571
R 2320d7d2beaa3603b04f97d8f781e745
U drh
Z a203462f3c9a0a6b91b58e9eba1fc107
Z b76abd0e65d7599880199d2a9894cd84

View File

@ -1 +1 @@
4ded1965eb83dee0f28c27ba935d615c77331571
1e3d0d094776c2a429fa2a3eebc036a0b6374862

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree_rb.c,v 1.3 2003/04/16 01:28:16 drh Exp $
** $Id: btree_rb.c,v 1.4 2003/04/18 22:52:39 drh Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
@ -69,7 +69,7 @@ struct BtRollbackOp {
#define ROLLBACK_DROP 4 /* Drop a table */
struct Btree {
BtOps *pOps; /* Function table */
BtOps *pOps; /* Function table */
int aMetaData[SQLITE_N_BTREE_META];
int next_idx; /* next available table index */
@ -89,10 +89,10 @@ struct Btree {
#define TRANS_INTRANSACTION 1 /* A transaction is in progress */
#define TRANS_INCHECKPOINT 2 /* A checkpoint is in progress */
#define TRANS_ROLLBACK 3 /* We are currently rolling back a checkpoint or
* transaction. */
* transaction. */
struct BtCursor {
BtCursorOps *pOps; /* Function table */
BtCursorOps *pOps; /* Function table */
Btree *pBtree;
BtRbTree *pTree;
int iTree; /* Index of pTree in pBtree */
@ -298,61 +298,61 @@ static void check_redblack_tree(BtRbTree * tree, char ** msg)
while( pNode ){
switch( prev_step ){
case 0:
if( pNode->pLeft ){
pNode = pNode->pLeft;
}else{
prev_step = 1;
}
break;
if( pNode->pLeft ){
pNode = pNode->pLeft;
}else{
prev_step = 1;
}
break;
case 1:
if( pNode->pRight ){
pNode = pNode->pRight;
prev_step = 0;
}else{
prev_step = 2;
}
break;
if( pNode->pRight ){
pNode = pNode->pRight;
prev_step = 0;
}else{
prev_step = 2;
}
break;
case 2:
/* Check red-black property (1) */
if( !pNode->isBlack &&
( (pNode->pLeft && !pNode->pLeft->isBlack) ||
(pNode->pRight && !pNode->pRight->isBlack) )
){
char buf[128];
sprintf(buf, "Red node with red child at %p\n", pNode);
*msg = append_val(*msg, buf);
*msg = append_node(*msg, tree->pHead, 0);
*msg = append_val(*msg, "\n");
}
/* Check red-black property (1) */
if( !pNode->isBlack &&
( (pNode->pLeft && !pNode->pLeft->isBlack) ||
(pNode->pRight && !pNode->pRight->isBlack) )
){
char buf[128];
sprintf(buf, "Red node with red child at %p\n", pNode);
*msg = append_val(*msg, buf);
*msg = append_node(*msg, tree->pHead, 0);
*msg = append_val(*msg, "\n");
}
/* Check red-black property (2) */
{
int leftHeight = 0;
int rightHeight = 0;
if( pNode->pLeft ){
leftHeight += pNode->pLeft->nBlackHeight;
leftHeight += (pNode->pLeft->isBlack?1:0);
}
if( pNode->pRight ){
rightHeight += pNode->pRight->nBlackHeight;
rightHeight += (pNode->pRight->isBlack?1:0);
}
if( leftHeight != rightHeight ){
char buf[128];
sprintf(buf, "Different black-heights at %p\n", pNode);
*msg = append_val(*msg, buf);
*msg = append_node(*msg, tree->pHead, 0);
*msg = append_val(*msg, "\n");
}
pNode->nBlackHeight = leftHeight;
}
/* Check red-black property (2) */
{
int leftHeight = 0;
int rightHeight = 0;
if( pNode->pLeft ){
leftHeight += pNode->pLeft->nBlackHeight;
leftHeight += (pNode->pLeft->isBlack?1:0);
}
if( pNode->pRight ){
rightHeight += pNode->pRight->nBlackHeight;
rightHeight += (pNode->pRight->isBlack?1:0);
}
if( leftHeight != rightHeight ){
char buf[128];
sprintf(buf, "Different black-heights at %p\n", pNode);
*msg = append_val(*msg, buf);
*msg = append_node(*msg, tree->pHead, 0);
*msg = append_val(*msg, "\n");
}
pNode->nBlackHeight = leftHeight;
}
if( pNode->pParent ){
if( pNode == pNode->pParent->pLeft ) prev_step = 1;
else prev_step = 2;
}
pNode = pNode->pParent;
break;
if( pNode->pParent ){
if( pNode == pNode->pParent->pLeft ) prev_step = 1;
else prev_step = 2;
}
pNode = pNode->pParent;
break;
default: assert(0);
}
}
@ -408,47 +408,47 @@ static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
}else{
if( pX->pParent == pGrandparent->pLeft ){
if( pX == pX->pParent->pRight ){
/* If pX is a right-child, do the following transform, essentially
* to change pX into a left-child:
* | |
* G(b) G(b)
* / \ / \
* P(r) U(b) X(r) U(b)
* \ /
* X(r) P(r) <-- new X
*
* BEFORE AFTER
*/
pX = pX->pParent;
leftRotate(pTree, pX);
}
if( pX == pX->pParent->pRight ){
/* If pX is a right-child, do the following transform, essentially
* to change pX into a left-child:
* | |
* G(b) G(b)
* / \ / \
* P(r) U(b) X(r) U(b)
* \ /
* X(r) P(r) <-- new X
*
* BEFORE AFTER
*/
pX = pX->pParent;
leftRotate(pTree, pX);
}
/* Do the following transform, which balances the tree :)
* | |
* G(b) P(b)
* / \ / \
* P(r) U(b) X(r) G(r)
* / \
* X(r) U(b)
*
* BEFORE AFTER
*/
assert( pGrandparent == pX->pParent->pParent );
pGrandparent->isBlack = 0;
pX->pParent->isBlack = 1;
rightRotate( pTree, pGrandparent );
/* Do the following transform, which balances the tree :)
* | |
* G(b) P(b)
* / \ / \
* P(r) U(b) X(r) G(r)
* / \
* X(r) U(b)
*
* BEFORE AFTER
*/
assert( pGrandparent == pX->pParent->pParent );
pGrandparent->isBlack = 0;
pX->pParent->isBlack = 1;
rightRotate( pTree, pGrandparent );
}else{
/* This code is symetric to the illustrated case above. */
if( pX == pX->pParent->pLeft ){
pX = pX->pParent;
rightRotate(pTree, pX);
}
assert( pGrandparent == pX->pParent->pParent );
pGrandparent->isBlack = 0;
pX->pParent->isBlack = 1;
leftRotate( pTree, pGrandparent );
/* This code is symetric to the illustrated case above. */
if( pX == pX->pParent->pLeft ){
pX = pX->pParent;
rightRotate(pTree, pX);
}
assert( pGrandparent == pX->pParent->pParent );
pGrandparent->isBlack = 0;
pX->pParent->isBlack = 1;
leftRotate( pTree, pGrandparent );
}
}
}
@ -470,7 +470,8 @@ static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
* properties have been violated, and pX has an "extra black". This function
* performs rotations and color-changes to re-balance the tree.
*/
static void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent)
static
void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent)
{
BtRbNode *pSib;
@ -479,58 +480,58 @@ static void do_delete_balancing(BtRbTree *pTree, BtRbNode *pX, BtRbNode *pParent
if( pX == pParent->pLeft ){
pSib = pParent->pRight;
if( pSib && !(pSib->isBlack) ){
pSib->isBlack = 1;
pParent->isBlack = 0;
leftRotate(pTree, pParent);
pSib = pParent->pRight;
pSib->isBlack = 1;
pParent->isBlack = 0;
leftRotate(pTree, pParent);
pSib = pParent->pRight;
}
if( !pSib ){
pX = pParent;
pX = pParent;
}else if(
(!pSib->pLeft || pSib->pLeft->isBlack) &&
(!pSib->pRight || pSib->pRight->isBlack) ) {
pSib->isBlack = 0;
pX = pParent;
(!pSib->pLeft || pSib->pLeft->isBlack) &&
(!pSib->pRight || pSib->pRight->isBlack) ) {
pSib->isBlack = 0;
pX = pParent;
}else{
if( (!pSib->pRight || pSib->pRight->isBlack) ){
if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
pSib->isBlack = 0;
rightRotate( pTree, pSib );
pSib = pParent->pRight;
}
pSib->isBlack = pParent->isBlack;
pParent->isBlack = 1;
if( pSib->pRight ) pSib->pRight->isBlack = 1;
leftRotate(pTree, pParent);
pX = pTree->pHead;
if( (!pSib->pRight || pSib->pRight->isBlack) ){
if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
pSib->isBlack = 0;
rightRotate( pTree, pSib );
pSib = pParent->pRight;
}
pSib->isBlack = pParent->isBlack;
pParent->isBlack = 1;
if( pSib->pRight ) pSib->pRight->isBlack = 1;
leftRotate(pTree, pParent);
pX = pTree->pHead;
}
}else{
pSib = pParent->pLeft;
if( pSib && !(pSib->isBlack) ){
pSib->isBlack = 1;
pParent->isBlack = 0;
rightRotate(pTree, pParent);
pSib = pParent->pLeft;
pSib->isBlack = 1;
pParent->isBlack = 0;
rightRotate(pTree, pParent);
pSib = pParent->pLeft;
}
if( !pSib ){
pX = pParent;
pX = pParent;
}else if(
(!pSib->pLeft || pSib->pLeft->isBlack) &&
(!pSib->pRight || pSib->pRight->isBlack) ){
pSib->isBlack = 0;
pX = pParent;
(!pSib->pRight || pSib->pRight->isBlack) ){
pSib->isBlack = 0;
pX = pParent;
}else{
if( (!pSib->pLeft || pSib->pLeft->isBlack) ){
if( pSib->pRight ) pSib->pRight->isBlack = 1;
pSib->isBlack = 0;
leftRotate( pTree, pSib );
pSib = pParent->pLeft;
}
pSib->isBlack = pParent->isBlack;
pParent->isBlack = 1;
if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
rightRotate(pTree, pParent);
pX = pTree->pHead;
if( (!pSib->pLeft || pSib->pLeft->isBlack) ){
if( pSib->pRight ) pSib->pRight->isBlack = 1;
pSib->isBlack = 0;
leftRotate( pTree, pSib );
pSib = pParent->pLeft;
}
pSib->isBlack = pParent->isBlack;
pParent->isBlack = 1;
if( pSib->pLeft ) pSib->pLeft->isBlack = 1;
rightRotate(pTree, pParent);
pX = pTree->pHead;
}
}
pParent = pX->pParent;
@ -573,10 +574,7 @@ int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree)
*ppBtree = (Btree *)sqliteMalloc(sizeof(Btree));
sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0);
/* Create binary trees for tables 0, 1 and 2. SQLite assumes these
* tables always exist. At least I think so? */
btreeCreateTable(*ppBtree, 0);
btreeCreateTable(*ppBtree, 1);
/* Create a binary tree for the SQLITE_MASTER table at location 2 */
btreeCreateTable(*ppBtree, 2);
(*ppBtree)->next_idx = 3;
(*ppBtree)->pOps = &sqliteBtreeOps;
@ -620,10 +618,9 @@ static int memBtreeDropTable(Btree* tree, int n)
assert( tree->eTransState != TRANS_NONE );
memBtreeClearTable(tree, n);
pTree = sqliteHashFind(&tree->tblHash, 0, n);
pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
assert(pTree);
sqliteFree(pTree);
sqliteHashInsert(&tree->tblHash, 0, n, 0);
if( tree->eTransState != TRANS_ROLLBACK ){
BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
@ -636,7 +633,7 @@ static int memBtreeDropTable(Btree* tree, int n)
}
static int memBtreeKeyCompare(BtCursor* pCur, const void *pKey, int nKey,
int nIgnore, int *pRes)
int nIgnore, int *pRes)
{
assert(pCur);
@ -647,7 +644,7 @@ static int memBtreeKeyCompare(BtCursor* pCur, const void *pKey, int nKey,
*pRes = -1;
}else{
*pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey-nIgnore,
pKey, nKey);
pKey, nKey);
}
}
return SQLITE_OK;
@ -681,7 +678,7 @@ static int memBtreeCursor(Btree* tree, int iTable, int wrFlag, BtCursor **ppCur)
* If the key exists already in the tree, just replace the data.
*/
static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
const void *pDataInput, int nData)
const void *pDataInput, int nData)
{
void * pData;
int match;
@ -715,18 +712,18 @@ static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
pNode->pData = pData;
if( pCur->pNode ){
switch( match ){
case -1:
assert( !pCur->pNode->pRight );
pNode->pParent = pCur->pNode;
pCur->pNode->pRight = pNode;
break;
case 1:
assert( !pCur->pNode->pLeft );
pNode->pParent = pCur->pNode;
pCur->pNode->pLeft = pNode;
break;
default:
assert(0);
case -1:
assert( !pCur->pNode->pRight );
pNode->pParent = pCur->pNode;
pCur->pNode->pRight = pNode;
break;
case 1:
assert( !pCur->pNode->pLeft );
pNode->pParent = pCur->pNode;
pCur->pNode->pLeft = pNode;
break;
default:
assert(0);
}
}else{
pCur->pTree->pHead = pNode;
@ -800,11 +797,11 @@ static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey, int *pRes)
pTmp = pCur->pNode;
switch( *pRes ){
case 1: /* cursor > key */
pCur->pNode = pCur->pNode->pLeft;
break;
pCur->pNode = pCur->pNode->pLeft;
break;
case -1: /* cursor < key */
pCur->pNode = pCur->pNode->pRight;
break;
pCur->pNode = pCur->pNode->pRight;
break;
}
}
@ -894,8 +891,8 @@ static int memBtreeDelete(BtCursor* pCur)
pCur->eSkip = SKIP_PREV;
}
if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){
sqliteFree(pZ->pKey);
sqliteFree(pZ->pData);
sqliteFree(pZ->pKey);
sqliteFree(pZ->pData);
}
}
@ -908,7 +905,7 @@ static int memBtreeDelete(BtCursor* pCur)
if( pZ->pParent ){
assert( pZ == pZ->pParent->pLeft || pZ == pZ->pParent->pRight );
ppParentSlot = ((pZ == pZ->pParent->pLeft)
?&pZ->pParent->pLeft:&pZ->pParent->pRight);
?&pZ->pParent->pLeft:&pZ->pParent->pRight);
*ppParentSlot = pChild;
}else{
pCur->pTree->pHead = pChild;
@ -951,22 +948,22 @@ static int memBtreeClearTable(Btree* tree, int n)
else {
BtRbNode *pTmp = pNode->pParent;
if( tree->eTransState == TRANS_ROLLBACK ){
sqliteFree( pNode->pKey );
sqliteFree( pNode->pData );
sqliteFree( pNode->pKey );
sqliteFree( pNode->pData );
}else{
BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
pRollbackOp->eOp = ROLLBACK_INSERT;
pRollbackOp->iTab = n;
pRollbackOp->nKey = pNode->nKey;
pRollbackOp->pKey = pNode->pKey;
pRollbackOp->nData = pNode->nData;
pRollbackOp->pData = pNode->pData;
btreeLogRollbackOp(tree, pRollbackOp);
BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
pRollbackOp->eOp = ROLLBACK_INSERT;
pRollbackOp->iTab = n;
pRollbackOp->nKey = pNode->nKey;
pRollbackOp->pKey = pNode->pKey;
pRollbackOp->nData = pNode->nData;
pRollbackOp->pData = pNode->pData;
btreeLogRollbackOp(tree, pRollbackOp);
}
sqliteFree( pNode );
if( pTmp ){
if( pTmp->pLeft == pNode ) pTmp->pLeft = 0;
else if( pTmp->pRight == pNode ) pTmp->pRight = 0;
if( pTmp->pLeft == pNode ) pTmp->pLeft = 0;
else if( pTmp->pRight == pNode ) pTmp->pRight = 0;
}
pNode = pTmp;
}
@ -1016,13 +1013,13 @@ static int memBtreeNext(BtCursor* pCur, int *pRes)
if( pCur->pNode->pRight ){
pCur->pNode = pCur->pNode->pRight;
while( pCur->pNode->pLeft )
pCur->pNode = pCur->pNode->pLeft;
pCur->pNode = pCur->pNode->pLeft;
}else{
BtRbNode * pX = pCur->pNode;
pCur->pNode = pX->pParent;
while( pCur->pNode && (pCur->pNode->pRight == pX) ){
pX = pCur->pNode;
pCur->pNode = pX->pParent;
pX = pCur->pNode;
pCur->pNode = pX->pParent;
}
}
}
@ -1043,13 +1040,13 @@ static int memBtreePrevious(BtCursor* pCur, int *pRes)
if( pCur->pNode->pLeft ){
pCur->pNode = pCur->pNode->pLeft;
while( pCur->pNode->pRight )
pCur->pNode = pCur->pNode->pRight;
pCur->pNode = pCur->pNode->pRight;
}else{
BtRbNode * pX = pCur->pNode;
pCur->pNode = pX->pParent;
while( pCur->pNode && (pCur->pNode->pLeft == pX) ){
pX = pCur->pNode;
pCur->pNode = pX->pParent;
pX = pCur->pNode;
pCur->pNode = pX->pParent;
}
}
}
@ -1152,11 +1149,11 @@ static char *memBtreeIntegrityCheck(Btree* tree, int* aRoot, int nRoot)
static int memBtreeClose(Btree* tree)
{
HashElem *p;
for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
tree->eTransState = TRANS_ROLLBACK;
memBtreeClearTable(tree, sqliteHashKeysize(p));
sqliteFree(sqliteHashData(p));
memBtreeDropTable(tree, sqliteHashKeysize(p));
}
sqliteHashClear(&tree->tblHash);
sqliteFree(tree);
return SQLITE_OK;
}
@ -1220,30 +1217,30 @@ static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList)
while( pList ){
switch( pList->eOp ){
case ROLLBACK_INSERT:
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
assert(cur.pTree);
cur.iTree = pList->iTab;
cur.eSkip = SKIP_NONE;
memBtreeInsert( &cur, pList->pKey,
pList->nKey, pList->pData, pList->nData );
break;
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
assert(cur.pTree);
cur.iTree = pList->iTab;
cur.eSkip = SKIP_NONE;
memBtreeInsert( &cur, pList->pKey,
pList->nKey, pList->pData, pList->nData );
break;
case ROLLBACK_DELETE:
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
assert(cur.pTree);
cur.iTree = pList->iTab;
cur.eSkip = SKIP_NONE;
memBtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
assert(res == 0);
memBtreeDelete( &cur );
break;
cur.pTree = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
assert(cur.pTree);
cur.iTree = pList->iTab;
cur.eSkip = SKIP_NONE;
memBtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
assert(res == 0);
memBtreeDelete( &cur );
break;
case ROLLBACK_CREATE:
btreeCreateTable(pBtree, pList->iTab);
break;
btreeCreateTable(pBtree, pList->iTab);
break;
case ROLLBACK_DROP:
memBtreeDropTable(pBtree, pList->iTab);
break;
memBtreeDropTable(pBtree, pList->iTab);
break;
default:
assert(0);
assert(0);
}
sqliteFree(pList->pKey);
sqliteFree(pList->pData);