Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add some missing comments and fix other minor code issues in sqlite3ota.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | ota-update |
Files: | files | file ages | folders |
SHA1: |
718fd8b673d6557dd0eaad03e6a3332b |
User & Date: | dan 2015-02-20 14:36:16.318 |
Context
2015-02-21
| ||
20:08 | Fix some problems with resuming ota updates if saving the state is interrupted by a power failure or system crash. (check-in: 6d5ed70d0d user: dan tags: ota-update) | |
2015-02-20
| ||
14:36 | Add some missing comments and fix other minor code issues in sqlite3ota.c. (check-in: 718fd8b673 user: dan tags: ota-update) | |
2015-02-19
| ||
19:59 | Ensure the mutex used to protect the linked list of all main database files opened by a single ota vfs is allocated. (check-in: 9c8682d665 user: dan tags: ota-update) | |
Changes
Changes to ext/ota/sqlite3ota.c.
︙ | ︙ | |||
280 281 282 283 284 285 286 | int nStep; /* Rows processed for current object */ int nProgress; /* Rows processed for all objects */ OtaObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created ota vfs */ ota_file *pTargetFd; /* File handle open on target db */ /* The following state variables are used as part of the incremental | | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | int nStep; /* Rows processed for current object */ int nProgress; /* Rows processed for all objects */ OtaObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created ota vfs */ ota_file *pTargetFd; /* File handle open on target db */ /* The following state variables are used as part of the incremental ** checkpoint stage (eStage==OTA_STAGE_CKPT). See comments surrounding ** function otaSetupCheckpoint() for details. */ u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */ u32 mLock; int nFrame; /* Entries in aFrame[] array */ int nFrameAlloc; /* Allocated size of aFrame[] array */ OtaFrame *aFrame; int pgsz; u8 *aBuf; |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 | if( p->rc==SQLITE_OK ){ iRet = ((i64)ptr[10] << 32) + ptr[11]; } } return iRet; } static void otaSetupCheckpoint(sqlite3ota *p, OtaState *pState){ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->db, "SELECT * FROM sqlite_master", 0, 0, 0); } } if( p->rc==SQLITE_OK ){ int rc2; p->eStage = OTA_STAGE_CAPTURE; rc2 = sqlite3_exec(p->db, "PRAGMA main.wal_checkpoint=restart", 0, 0, 0); if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } if( p->rc==SQLITE_OK ){ p->eStage = OTA_STAGE_CKPT; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 | if( p->rc==SQLITE_OK ){ iRet = ((i64)ptr[10] << 32) + ptr[11]; } } return iRet; } /* ** This function is called as part of initializing or reinitializing an ** incremental checkpoint. ** ** It populates the sqlite3ota.aFrame[] array with the set of ** (wal frame -> db page) copy operations required to checkpoint the ** current wal file, and obtains the set of shm locks required to safely ** perform the copy operations directly on the file-system. ** ** If argument pState is not NULL, then the incremental checkpoint is ** being resumed. In this case, if the checksum of the wal-index-header ** following recovery is not the same as the checksum saved in the OtaState ** object, then the ota handle is set to DONE state. This occurs if some ** other client appends a transaction to the wal file in the middle of ** an incremental checkpoint. */ static void otaSetupCheckpoint(sqlite3ota *p, OtaState *pState){ /* If pState is NULL, then the wal file may not have been opened and ** recovered. Running a read-statement here to ensure that doing so ** does not interfere with the "capture" process below. */ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->db, "SELECT * FROM sqlite_master", 0, 0, 0); } } /* Assuming no error has occurred, run a "restart" checkpoint with the ** sqlite3ota.eStage variable set to CAPTURE. This turns on the following ** special behaviour in the ota VFS: ** ** * If the exclusive shm WRITER or READ0 lock cannot be obtained, ** the checkpoint fails with SQLITE_BUSY (normally SQLite would ** proceed with running a passive checkpoint instead of failing). ** ** * Attempts to read from the *-wal file or write to the database file ** do not perform any IO. Instead, the frame/page combinations that ** would be read/written are recorded in the sqlite3ota.aFrame[] ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[] ** array populated with a set of (frame -> page) mappings. Because the ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy ** data from the wal file into the database file according to the ** contents of aFrame[]. */ if( p->rc==SQLITE_OK ){ int rc2; p->eStage = OTA_STAGE_CAPTURE; rc2 = sqlite3_exec(p->db, "PRAGMA main.wal_checkpoint=restart", 0, 0, 0); if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } if( p->rc==SQLITE_OK ){ p->eStage = OTA_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = otaMalloc(p, p->pgsz); p->iWalCksum = otaShmChecksum(p); } if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){ p->rc = SQLITE_DONE; p->eStage = OTA_STAGE_DONE; } } /* ** Called when iAmt bytes are read from offset iOff of the wal file while ** the ota object is in capture mode. Record the frame number of the frame ** being read in the aFrame[] array. */ static int otaCaptureWalRead(sqlite3ota *pOta, i64 iOff, int iAmt){ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0); u32 iFrame; if( pOta->mLock!=mReq ){ pOta->rc = SQLITE_BUSY; return SQLITE_INTERNAL; |
︙ | ︙ | |||
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 | if( pOta->iMaxFrame<iFrame ) pOta->iMaxFrame = iFrame; pOta->aFrame[pOta->nFrame].iWalFrame = iFrame; pOta->aFrame[pOta->nFrame].iDbPage = 0; pOta->nFrame++; return SQLITE_OK; } static int otaCaptureDbWrite(sqlite3ota *pOta, i64 iOff){ pOta->aFrame[pOta->nFrame-1].iDbPage = (u32)(iOff / pOta->pgsz) + 1; return SQLITE_OK; } static void otaCheckpointFrame(sqlite3ota *p, OtaFrame *pFrame){ sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; sqlite3_file *pDb = p->pTargetFd->pReal; i64 iOff; assert( p->rc==SQLITE_OK ); iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24; | > > > > > > > > > > | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 | if( pOta->iMaxFrame<iFrame ) pOta->iMaxFrame = iFrame; pOta->aFrame[pOta->nFrame].iWalFrame = iFrame; pOta->aFrame[pOta->nFrame].iDbPage = 0; pOta->nFrame++; return SQLITE_OK; } /* ** Called when a page of data is written to offset iOff of the database ** file while the ota handle is in capture mode. Record the page number ** of the page being written in the aFrame[] array. */ static int otaCaptureDbWrite(sqlite3ota *pOta, i64 iOff){ pOta->aFrame[pOta->nFrame-1].iDbPage = (u32)(iOff / pOta->pgsz) + 1; return SQLITE_OK; } /* ** This is called as part of an incremental checkpoint operation. Copy ** a single frame of data from the wal file into the database file, as ** indicated by the OtaFrame object. */ static void otaCheckpointFrame(sqlite3ota *p, OtaFrame *pFrame){ sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; sqlite3_file *pDb = p->pTargetFd->pReal; i64 iOff; assert( p->rc==SQLITE_OK ); iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24; |
︙ | ︙ | |||
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 | if( res==0 ){ otaBadControlError(p); } return res; } #ifdef SQLITE_DEBUG static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){ const char *zCol = sqlite3_column_name(pStmt, iCol); assert( 0==sqlite3_stricmp(zName, zCol) ); } #else # define assertColumnName(x,y,z) #endif | > > > | 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 | if( res==0 ){ otaBadControlError(p); } return res; } #ifdef SQLITE_DEBUG /* ** Assert that column iCol of statement pStmt is named zName. */ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){ const char *zCol = sqlite3_column_name(pStmt, iCol); assert( 0==sqlite3_stricmp(zName, zCol) ); } #else # define assertColumnName(x,y,z) #endif |
︙ | ︙ | |||
2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 | } if( p->rc==SQLITE_OK ){ otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1); } } } static void otaSaveState(sqlite3ota *p, int eStage){ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ sqlite3_stmt *pInsert = 0; int rc; assert( p->zErrmsg==0 ); rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, | > > > > > | 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 | } if( p->rc==SQLITE_OK ){ otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1); } } } /* ** Update the contents of the ota_state table within the ota database. The ** value stored in the OTA_STATE_STAGE column is eStage. All other values ** are determined by inspecting the ota handle passed as the first argument. */ static void otaSaveState(sqlite3ota *p, int eStage){ if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){ sqlite3_stmt *pInsert = 0; int rc; assert( p->zErrmsg==0 ); rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, |
︙ | ︙ | |||
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 | } return p->rc; }else{ return SQLITE_NOMEM; } } static void otaFreeState(OtaState *p){ if( p ){ sqlite3_free(p->zTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } } | > > > | 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 | } return p->rc; }else{ return SQLITE_NOMEM; } } /* ** Free an OtaState object allocated by otaLoadState(). */ static void otaFreeState(OtaState *p){ if( p ){ sqlite3_free(p->zTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } } |
︙ | ︙ | |||
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 | rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; p->rc = rc; return pRet; } static int otaStrCompare(const char *z1, const char *z2){ if( z1==0 && z2==0 ) return 0; if( z1==0 || z2==0 ) return 1; return (sqlite3_stricmp(z1, z2)!=0); } | > > > > > > > > > > > > > > > | | 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 | rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; p->rc = rc; return pRet; } /* ** Compare strings z1 and z2, returning 0 if they are identical, or non-zero ** otherwise. Either or both argument may be NULL. Two NULL values are ** considered equal, and NULL is considered distinct from all other values. */ static int otaStrCompare(const char *z1, const char *z2){ if( z1==0 && z2==0 ) return 0; if( z1==0 || z2==0 ) return 1; return (sqlite3_stricmp(z1, z2)!=0); } /* ** This function is called as part of sqlite3ota_open() when initializing ** an ota handle in OAL stage. If the ota update has not started (i.e. ** the ota_state table was empty) it is a no-op. Otherwise, it arranges ** things so that the next call to sqlite3ota_step() continues on from ** where the previous ota handle left off. ** ** If an error occurs, an error code and error message are left in the ** ota handle passed as the first argument. */ static void otaSetupOal(sqlite3ota *p, OtaState *pState){ assert( p->rc==SQLITE_OK ); if( pState->zTbl ){ OtaObjIter *pIter = &p->objiter; int rc = SQLITE_OK; while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup || otaStrCompare(pIter->zIdx, pState->zIdx) |
︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 | static void otaDeleteOalFile(sqlite3ota *p){ char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); unlink(zOal); sqlite3_free(zOal); } static void otaCreateVfs(sqlite3ota *p){ int rnd; char zRnd[64]; assert( p->rc==SQLITE_OK ); sqlite3_randomness(sizeof(int), (void*)&rnd); sprintf(zRnd, "ota_vfs_%d", rnd); p->rc = sqlite3ota_create_vfs(zRnd, 0); if( p->rc==SQLITE_OK ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd); assert( pVfs ); p->zVfsName = pVfs->zName; } } static void otaDeleteVfs(sqlite3ota *p){ if( p->zVfsName ){ sqlite3ota_destroy_vfs(p->zVfsName); p->zVfsName = 0; } } | > > > > > > > > > > | 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | static void otaDeleteOalFile(sqlite3ota *p){ char *zOal = sqlite3_mprintf("%s-oal", p->zTarget); assert( p->rc==SQLITE_OK && p->zErrmsg==0 ); unlink(zOal); sqlite3_free(zOal); } /* ** Allocate a private ota VFS for the ota handle passed as the only ** argument. This VFS will be used unless the call to sqlite3ota_open() ** specified a URI with a vfs=? option in place of a target database ** file name. */ static void otaCreateVfs(sqlite3ota *p){ int rnd; char zRnd[64]; assert( p->rc==SQLITE_OK ); sqlite3_randomness(sizeof(int), (void*)&rnd); sprintf(zRnd, "ota_vfs_%d", rnd); p->rc = sqlite3ota_create_vfs(zRnd, 0); if( p->rc==SQLITE_OK ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd); assert( pVfs ); p->zVfsName = pVfs->zName; } } /* ** Destroy the private VFS created for the ota handle passed as the only ** argument by an earlier call to otaCreateVfs(). */ static void otaDeleteVfs(sqlite3ota *p){ if( p->zVfsName ){ sqlite3ota_destroy_vfs(p->zVfsName); p->zVfsName = 0; } } |
︙ | ︙ | |||
2419 2420 2421 2422 2423 2424 2425 | /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = otaObjIterFirst(p, &p->objiter); } if( p->rc==SQLITE_OK ){ | | < | 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 | /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = otaObjIterFirst(p, &p->objiter); } if( p->rc==SQLITE_OK ){ otaSetupOal(p, pState); } }else if( p->eStage==OTA_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==OTA_STAGE_CKPT ){ otaSetupCheckpoint(p, pState); }else if( p->eStage==OTA_STAGE_DONE ){ p->rc = SQLITE_DONE; }else{ p->rc = SQLITE_CORRUPT; } } |
︙ | ︙ | |||
2790 2791 2792 2793 2794 2795 2796 | */ static int otaVfsDeviceCharacteristics(sqlite3_file *pFile){ ota_file *p = (ota_file *)pFile; return p->pReal->pMethods->xDeviceCharacteristics(p->pReal); } /* | | | 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 | */ static int otaVfsDeviceCharacteristics(sqlite3_file *pFile){ ota_file *p = (ota_file *)pFile; return p->pReal->pMethods->xDeviceCharacteristics(p->pReal); } /* ** Take or release a shared-memory lock. */ static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ ota_file *p = (ota_file*)pFile; sqlite3ota *pOta = p->pOta; int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION |
︙ | ︙ | |||
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 | } } } return rc; } static int otaVfsShmMap( sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp ){ | > > > | 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 | } } } return rc; } /* ** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file. */ static int otaVfsShmMap( sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp ){ |
︙ | ︙ | |||
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 | ** Memory barrier. */ static void otaVfsShmBarrier(sqlite3_file *pFile){ ota_file *p = (ota_file *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){ ota_file *p = (ota_file*)pFile; int rc = SQLITE_OK; int eStage = (p->pOta ? p->pOta->eStage : 0); assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){ /* no-op */ }else{ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } static ota_file *otaFindMaindb(ota_vfs *pOtaVfs, const char *zWal){ ota_file *pDb; sqlite3_mutex_enter(pOtaVfs->mutex); for(pDb=pOtaVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext); sqlite3_mutex_leave(pOtaVfs->mutex); return pDb; } | > > > > > > > > > | 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 | ** Memory barrier. */ static void otaVfsShmBarrier(sqlite3_file *pFile){ ota_file *p = (ota_file *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } /* ** The xShmUnmap method. */ static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){ ota_file *p = (ota_file*)pFile; int rc = SQLITE_OK; int eStage = (p->pOta ? p->pOta->eStage : 0); assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); if( eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_MOVE ){ /* no-op */ }else{ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } /* ** Given that zWal points to a buffer containing a wal file name passed to ** either the xOpen() or xAccess() VFS method, return a pointer to the ** file-handle opened by the same database connection on the corresponding ** database file. */ static ota_file *otaFindMaindb(ota_vfs *pOtaVfs, const char *zWal){ ota_file *pDb; sqlite3_mutex_enter(pOtaVfs->mutex); for(pDb=pOtaVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext); sqlite3_mutex_leave(pOtaVfs->mutex); return pDb; } |
︙ | ︙ | |||
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 | ** Return the current time as a Julian Day number in *pTimeOut. */ static int otaVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs; return pRealVfs->xCurrentTime(pRealVfs, pTimeOut); } static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return 0; } void sqlite3ota_destroy_vfs(const char *zName){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); if( pVfs && pVfs->xOpen==otaVfsOpen ){ sqlite3_mutex_free(((ota_vfs*)pVfs)->mutex); sqlite3_vfs_unregister(pVfs); sqlite3_free(pVfs); } } int sqlite3ota_create_vfs(const char *zName, const char *zParent){ /* Template for VFS */ static sqlite3_vfs vfs_template = { 1, /* iVersion */ 0, /* szOsFile */ 0, /* mxPathname */ | > > > > > > > > > > > > | 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 | ** Return the current time as a Julian Day number in *pTimeOut. */ static int otaVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs; return pRealVfs->xCurrentTime(pRealVfs, pTimeOut); } /* ** No-op. */ static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return 0; } /* ** Deregister and destroy an OTA vfs created by an earlier call to ** sqlite3ota_create_vfs(). */ void sqlite3ota_destroy_vfs(const char *zName){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); if( pVfs && pVfs->xOpen==otaVfsOpen ){ sqlite3_mutex_free(((ota_vfs*)pVfs)->mutex); sqlite3_vfs_unregister(pVfs); sqlite3_free(pVfs); } } /* ** Create an OTA VFS named zName that accesses the underlying file-system ** via existing VFS zParent. The new object is registered as a non-default ** VFS with SQLite before returning. */ int sqlite3ota_create_vfs(const char *zName, const char *zParent){ /* Template for VFS */ static sqlite3_vfs vfs_template = { 1, /* iVersion */ 0, /* szOsFile */ 0, /* mxPathname */ |
︙ | ︙ |
Changes to ext/ota/sqlite3ota.h.
︙ | ︙ | |||
306 307 308 309 310 311 312 313 314 315 316 317 318 319 | ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current OTA update was started. */ sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta); /* ** Part of the OTA implementation uses a custom VFS object. Usually, this ** object is created and deleted automatically by OTA. ** ** The exception is for applications that also use zipvfs. In this case, ** the custom VFS must be explicitly created by the user before the OTA ** handle is opened. The OTA VFS should be installed so that the zipvfs ** VFS uses the OTA VFS, which in turn uses any other VFS layers in use | > > > > | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current OTA update was started. */ sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta); /* ** Create an OTA VFS named zName that accesses the underlying file-system ** via existing VFS zParent. The new object is registered as a non-default ** VFS with SQLite before returning. ** ** Part of the OTA implementation uses a custom VFS object. Usually, this ** object is created and deleted automatically by OTA. ** ** The exception is for applications that also use zipvfs. In this case, ** the custom VFS must be explicitly created by the user before the OTA ** handle is opened. The OTA VFS should be installed so that the zipvfs ** VFS uses the OTA VFS, which in turn uses any other VFS layers in use |
︙ | ︙ |