Zipvfs C Example Code
This page contains example C code demonstrating how to use the Zipvfs module. Two examples are provided:
- Example One: How to create a VFS that uses the popular compression library zlib to compress data.
- Example Two: How to create a routine that compacts the database if doing so would result in disk-space savings of 10% or greater.
Using Zlib Compression With Zipvfs
This example demonstrates how to create a Zipvfs VFS that uses zlib to compress data and how to open a database connection that uses it. This example uses the zipvfs_create_vfs() API.
Functions compress(), uncompress() and compressBound() are utility functions supplied by the zlib library.
/* Zlib xCompressBound callback. */
static int zlibBound(void *pCtx, int nByte){
return compressBound(nByte);
}
/* Zlib xCompress callback. */
static int zlibCompress(void *pCtx, char *aDest, int *pnDest, char *aSrc, int nSrc){
uLongf n = *pnDest; /* In/out buffer size for compress() */
int rc; /* compress() return code */
rc = compress((Bytef*)aDest, &n, (Bytef*)aSrc, nSrc);
*pnDest = n;
return (rc==Z_OK ? SQLITE_OK : SQLITE_ERROR);
}
/* Zlib xUncompress callback. */
static int zlibUncompress(void *pCtx, char *aDest, int *pnDest, char *aSrc, int nSrc){
uLongf n = *pnDest; /* In/out buffer size for uncompress() */
int rc; /* uncompress() return code */
rc = uncompress((Bytef*)aDest, &n, (Bytef*)aSrc, nSrc);
*pnDest = n;
return (rc==Z_OK ? SQLITE_OK : SQLITE_ERROR);
}
/*
** Open a connection to a Zipvfs database file that uses zlib to compress
** data. If the connection is opened successfully, the new database handle
** is stored in *pDb and SQLITE_OK is returned. Otherwise, an error code
** is returned.
**
** The first time this function is called it creates a VFS that uses
** zlib to use with the new database connection. Each subsequent call reuses
** the same VFS. Note that there is a race condition in this code since the
** calls to check if the VFS has already been created and to actually create
** it are not protected by any kind of mutex primitive.
*/
int open_connection(const char *zName, sqlite3 **pDb){
/* Check if the VFS has already been created. If not, try to create it.
** If an error occurs while trying to create the new VFS (unlikely), return
** an error code immediately. Otherwise, proceed.
**
** The second parameter passed to zipvfs_create_vfs() is a NULL pointer.
** This means the new VFS will use the current default VFS to read and write
** the Zipvfs database file. This is normally the desired behaviour.
*/
if( sqlite3_vfs_find("zlib")==0 ){
int rc = zipvfs_create_vfs("zlib", 0, 0, zlibBound, zlibCompress, zlibUncompress);
if( rc!=SQLITE_OK ){
*pDb = 0;
return rc;
}
}
/* Open a database connection using the VFS "zlib". */
return sqlite3_open_v2(zName, pDb, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "zlib");
}
Compacting a Database
This example demonstrates using the ZIPVFS_CTRL_STAT and ZIPVFS_CTRL_COMPACT file-control operations together to selectively compact a zipvfs database file based on the amount of disk space that can be reclaimed by doing so.
/*
** Parameter zName must be the name (e.g. "main") of a zipvfs database attached
** to database handle db. If doing so will reduce the size of the database
** file by approximately 10% or greater, then this routine compacts the file.
** So as not to require an excessive amount of temporary disk space, it does
** so using a series of incremental compact operations, each one compacting
** 500 KB of the file.
*/
int compact_database(sqlite3 *db, const char *zName){
ZipvfsStat stat; /* Stat data for zipvfs file. */
int rc; /* Return code of file_control() calls */
sqlite3_int64 nFree; /* Total number of free bytes in file */
rc = sqlite3_file_control(db, zName, ZIPVFS_CTRL_STAT, (void *)&stat);
if( rc!=SQLITE_OK ) return rc;
/* Calculate the total number of free bytes in the file. This is roughly
** the amount of disk space that could be freed by compacting the database.
** It is only a rough estimate as the size of the file on disk is rounded
** up to the nearest integer multiple of the page-size both before and after
** the compact operation. So in practice the number of bytes of disk space
** freed may be up to (pagesize-1) bytes less than or greater than the
** value calculated here.
*/
nFree = stat.nFreeByte + stat.nFragByte + stat.nGapByte;
/* stat.nFileByte is the current size of the zipvfs database. If nFree is
** greater than or equal to 10% of this, attempt to compact the database.
**
** The compact operation could be done using a single call to
** sqlite3_file_control() by specifying a NULL pointer as the final argument.
** However, this requires creating a journal file approximately the same
** size as the zipvfs database file itself, which may be very large. Instead,
** the following loop compacts the file using multiple transactions, each
** requiring a journal file approximately 500KB or less in size. If a power
** failure occurs during this loop, the file will not be corrupted. Following
** recovery, the next call to this function will pick up at the point where
** the power failure occurred.
*/
if( nFree>=(stat.nFileByte/10) ){
sqlite3_int64 nByte;
do{
nByte = 500 * 1024;
rc = sqlite3_file_control(db, zName, ZIPVFS_CTRL_COMPACT, (void *)&nByte);
}while( nByte>0 && rc==SQLITE_OK );
}
return rc;
}