@@ -3,6 +3,11 @@ import { FacadeVFS } from '../FacadeVFS.js';
33import * as VFS from '../VFS.js' ;
44import { WebLocksMixin } from '../WebLocksMixin.js' ;
55
6+ const RETRYABLE_ERRORS = new Set ( [
7+ 'TransactionInactiveError' ,
8+ 'InvalidStateError'
9+ ] ) ;
10+
611/**
712 * @typedef Metadata
813 * @property {string } name
@@ -482,25 +487,27 @@ export class IDBBatchAtomicVFS extends WebLocksMixin(FacadeVFS) {
482487 break ;
483488 case VFS . SQLITE_FCNTL_SYNC :
484489 this . log ?. ( 'xFileControl' , file . path , 'SYNC' ) ;
485- const commitMetadata = Object . assign ( { } , file . metadata ) ;
486- const prevFileSize = file . rollback . fileSize
487- this . #idb. q ( ( { metadata, blocks } ) => {
488- metadata . put ( commitMetadata ) ;
489-
490- // Remove old page versions.
491- for ( const offset of file . changedPages ) {
492- if ( offset < prevFileSize ) {
493- const range = IDBKeyRange . bound (
494- [ file . path , - offset , commitMetadata . version ] ,
495- [ file . path , - offset , Infinity ] ,
496- true ) ;
497- blocks . delete ( range ) ;
490+ if ( file . rollback ) {
491+ const commitMetadata = Object . assign ( { } , file . metadata ) ;
492+ const prevFileSize = file . rollback . fileSize
493+ this . #idb. q ( ( { metadata, blocks } ) => {
494+ metadata . put ( commitMetadata ) ;
495+
496+ // Remove old page versions.
497+ for ( const offset of file . changedPages ) {
498+ if ( offset < prevFileSize ) {
499+ const range = IDBKeyRange . bound (
500+ [ file . path , - offset , commitMetadata . version ] ,
501+ [ file . path , - offset , Infinity ] ,
502+ true ) ;
503+ blocks . delete ( range ) ;
504+ }
498505 }
499- }
500- file . changedPages . clear ( ) ;
501- } , 'rw' , file . txOptions ) ;
502- file . needsMetadataSync = false ;
503- file . rollback = null ;
506+ file . changedPages . clear ( ) ;
507+ } , 'rw' , file . txOptions ) ;
508+ file . needsMetadataSync = false ;
509+ file . rollback = null ;
510+ }
504511 break ;
505512 case VFS . SQLITE_FCNTL_BEGIN_ATOMIC_WRITE :
506513 // Every write transaction is atomic, so this is a no-op.
@@ -717,21 +724,21 @@ export class IDBContext {
717724 } ) ;
718725 }
719726
720- // @ts -ignore
721- // Create object store proxies.
722- const objectStores = [ ...tx . objectStoreNames ] . map ( name => {
723- return [ name , this . proxyStoreOrIndex ( tx . objectStore ( name ) ) ] ;
724- } ) ;
725-
726727 try {
728+ // @ts -ignore
729+ // Create object store proxies.
730+ const objectStores = [ ...tx . objectStoreNames ] . map ( name => {
731+ return [ name , this . proxyStoreOrIndex ( tx . objectStore ( name ) ) ] ;
732+ } ) ;
733+
727734 // Execute the function.
728735 return await f ( Object . fromEntries ( objectStores ) ) ;
729736 } catch ( e ) {
730737 // Use a new transaction if this one was inactive. This will
731738 // happen if the last request in the transaction completed
732739 // in a previous task but the transaction has not yet committed.
733- if ( ! i && e . name === 'TransactionInactiveError' ) {
734- this . log ?. ( 'TransactionInactiveError , retrying' ) ;
740+ if ( ! i && RETRYABLE_ERRORS . has ( e . name ) ) {
741+ this . log ?. ( ` ${ e . name } , retrying` ) ;
735742 tx = null ;
736743 continue ;
737744 }
0 commit comments