Index: src/rowhash.c ================================================================== --- src/rowhash.c +++ src/rowhash.c @@ -29,11 +29,11 @@ ** operations only look for INSERTs that occurred in prior batches. ** ** The caller is responsible for insuring that there are no duplicate ** INSERTs. ** -** $Id: rowhash.c,v 1.3 2009/04/21 16:15:15 drh Exp $ +** $Id: rowhash.c,v 1.4 2009/04/21 18:20:45 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** An upper bound on the size of heap allocations made by this module. @@ -123,11 +123,10 @@ ** rebuilding the hash table. The hash table is rebuilt after every ** batch of inserts. */ struct RowHashBlock { struct RowHashBlockData { - int nUsed; /* Num of aElem[] currently used in this block */ RowHashBlock *pNext; /* Next RowHashBlock object in list of them all */ } data; RowHashElem aElem[ROWHASH_ELEM_PER_BLOCK]; /* Available RowHashElem objects */ }; @@ -134,10 +133,11 @@ /* ** RowHash structure. References to a structure of this type are passed ** around and used as opaque handles by code in other modules. */ struct RowHash { + int nUsed; /* Number of used entries in first RowHashBlock */ int nEntry; /* Number of used entries over all RowHashBlocks */ int iBatch; /* The current insert batch number */ u8 nHeight; /* Height of tree of hash pages */ u8 nLinearLimit; /* Linear search limit (used if pHash==0) */ int nBucket; /* Number of buckets in hash table */ @@ -268,11 +268,13 @@ return SQLITE_NOMEM; } /* Insert all values into the hash-table. */ for(pBlock=p->pBlock; pBlock; pBlock=pBlock->data.pNext){ - RowHashElem * const pEnd = &pBlock->aElem[pBlock->data.nUsed]; + RowHashElem * const pEnd = &pBlock->aElem[ + pBlock==p->pBlock?p->nUsed:ROWHASH_ELEM_PER_BLOCK + ]; RowHashElem *pIter; for(pIter=pBlock->aElem; pIteriVal); pIter->pNext = *ppElem; *ppElem = pIter; @@ -352,23 +354,24 @@ *pp = p; } /* If the current RowHashBlock is full, or if the first RowHashBlock has ** not yet been allocated, allocate one now. */ - if( !p->pBlock || p->pBlock->data.nUsed==ROWHASH_ELEM_PER_BLOCK ){ + if( !p->pBlock || p->nUsed==ROWHASH_ELEM_PER_BLOCK ){ RowHashBlock *pBlock = (RowHashBlock*)sqlite3Malloc(sizeof(RowHashBlock)); if( !pBlock ){ return SQLITE_NOMEM; } - pBlock->data.nUsed = 0; pBlock->data.pNext = p->pBlock; p->pBlock = pBlock; + p->nUsed = 0; } + assert( p->nUsed==(p->nEntry % ROWHASH_ELEM_PER_BLOCK) ); /* Add iVal to the current RowHashBlock. */ - p->pBlock->aElem[p->pBlock->data.nUsed].iVal = iVal; - p->pBlock->data.nUsed++; + p->pBlock->aElem[p->nUsed].iVal = iVal; + p->nUsed++; p->nEntry++; return SQLITE_OK; } /* Index: src/test_async.c ================================================================== --- src/test_async.c +++ src/test_async.c @@ -8,11 +8,11 @@ ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** -** $Id: test_async.c,v 1.57 2009/04/07 11:21:29 danielk1977 Exp $ +** $Id: test_async.c,v 1.58 2009/04/21 18:20:45 danielk1977 Exp $ ** ** This file contains an example implementation of an asynchronous IO ** backend for SQLite. ** ** WHAT IS ASYNCHRONOUS I/O? @@ -71,11 +71,11 @@ ** file concurrently. From the point of view of the user, if all ** connections are from within a single process, there is no difference ** between the concurrency offered by "normal" SQLite and SQLite ** using the asynchronous backend. ** -** If connections from within multiple database files may access the +** If connections from within multiple processes may access the ** database file, the ENABLE_FILE_LOCKING symbol (see below) must be ** defined. If it is not defined, then no locks are established on ** the database file. In this case, if multiple processes access ** the database file, corruption will quickly result. **