DBD-SQLite
view release on metacpan or search on metacpan
/*
** This structure is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
int nChunkSize; /* In-memory chunk-size */
int nSpill; /* Bytes of data before flushing */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
const char *zJournal; /* Name of the journal file */
};
/*
** Read data from the in-memory journal file. This is the implementation
** of the sqlite3_vfs.xRead method.
void *zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite_int64 iOfst /* Begin reading at this offset */
){
MemJournal *p = (MemJournal *)pJfd;
u8 *zOut = zBuf;
int nRead = iAmt;
int iChunkOffset;
FileChunk *pChunk;
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
pChunk=pChunk->pNext
){
iOff += p->nChunkSize;
sqlite3_file *pReal = (sqlite3_file*)p;
MemJournal copy = *p;
memset(p, 0, sizeof(MemJournal));
rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
if( rc==SQLITE_OK ){
int nChunk = copy.nChunkSize;
i64 iOff = 0;
FileChunk *pIter;
for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
if( iOff + nChunk > copy.endpoint.iOffset ){
nChunk = copy.endpoint.iOffset - iOff;
}
rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
if( rc ) break;
iOff += nChunk;
}
if( rc==SQLITE_OK ){
/* No error has occurred. Free the in-memory buffers. */
memjrnlFreeChunks(copy.pFirst);
}
}
return rc;
}
/* If the contents of this write should be stored in memory */
else{
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required. The only exception to this is when
** the in-memory journal is being used by a connection using the
** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */
assert( iOfst<=p->endpoint.iOffset );
if( iOfst>0 && iOfst!=p->endpoint.iOffset ){
memjrnlTruncate(pJfd, iOfst);
}
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
}else{
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
assert( pChunk!=0 || iChunkOffset==0 );
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
if( !pNew ){
return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
pChunk = p->endpoint.pChunk = pNew;
}
assert( pChunk!=0 );
memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
}
}
}
return SQLITE_OK;
}
/*
** Truncate the in-memory file.
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 );
if( size<p->endpoint.iOffset ){
FileChunk *pIter = 0;
if( size==0 ){
memjrnlFreeChunks(p->pFirst);
p->pFirst = 0;
}else{
i64 iOff = p->nChunkSize;
for(pIter=p->pFirst; ALWAYS(pIter) && iOff<size; pIter=pIter->pNext){
iOff += p->nChunkSize;
}
if( ALWAYS(pIter) ){
memjrnlFreeChunks(pIter->pNext);
pIter->pNext = 0;
}
}
p->endpoint.pChunk = pIter;
p->endpoint.iOffset = size;
p->readpoint.pChunk = 0;
p->readpoint.iOffset = 0;
}
return SQLITE_OK;
}
/*
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
static int memjrnlSync(sqlite3_file *pJfd, int flags){
UNUSED_PARAMETER2(pJfd, flags);
return SQLITE_OK;
}
/*
** Query the size of the file in bytes.
*/
static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
MemJournal *p = (MemJournal *)pJfd;
*pSize = (sqlite_int64) p->endpoint.iOffset;
return SQLITE_OK;
}
/*
** Table of methods for MemJournal sqlite3_file object.
*/
static const struct sqlite3_io_methods MemJournalMethods = {
1, /* iVersion */
memjrnlClose, /* xClose */
memjrnlRead, /* xRead */
( run in 0.242 second using v1.01-cache-2.11-cpan-b61123c0432 )