@@ -34,6 +34,7 @@ interface FileSystemSyncAccessHandle extends FileSystemHandle {
3434}
3535
3636class PersistentFile {
37+ path : string ;
3738 fileHandle : FileSystemFileHandle ;
3839 accessHandle : null | FileSystemSyncAccessHandle = null ;
3940
@@ -47,7 +48,8 @@ class PersistentFile {
4748 handleRequestChannel : BroadcastChannel ;
4849 isHandleRequested = false ;
4950
50- constructor ( fileHandle ) {
51+ constructor ( path : string , fileHandle : FileSystemFileHandle ) {
52+ this . path = path ;
5153 this . fileHandle = fileHandle ;
5254 }
5355}
@@ -88,6 +90,20 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
8890 return ( this as unknown as WithModule ) . _module ;
8991 }
9092
93+ async prelock ( fileName : string ) : Promise < Disposable > {
94+ const file = this . persistentFiles . get ( '/' + fileName ) ;
95+ this . log ?.( 'prelock' , fileName , file ) ;
96+ await this . #requestAccessHandle( file ) ;
97+ this . log ?.( 'prelocked' , fileName ) ;
98+ const self = this ;
99+ return {
100+ [ Symbol . dispose ] ( ) {
101+ this . log ?.( 'prelock release' , fileName ) ;
102+ self . #releaseAccessHandle( file ) ;
103+ }
104+ } ;
105+ }
106+
91107 async #initialize( nTemporaryFiles ) {
92108 // Delete temporary directories no longer in use.
93109 const root = await navigator . storage . getDirectory ( ) ;
@@ -183,11 +199,11 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
183199 // Get access handles for the files.
184200 const file = new File ( path , flags ) ;
185201 file . persistentFile = this . persistentFiles . get ( path ) ;
186- await this . #requestAccessHandle( file ) ;
202+ await this . #requestAccessHandle( file . persistentFile ) ;
187203 } catch ( e ) {
188204 // Use an invalid persistent file to signal this error
189205 // for the retried open.
190- const persistentFile = new PersistentFile ( null ) ;
206+ const persistentFile = new PersistentFile ( path , null ) ;
191207 this . persistentFiles . set ( path , persistentFile ) ;
192208 console . error ( e ) ;
193209 }
@@ -205,7 +221,7 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
205221 ( async ( ) => {
206222 const file = new File ( path , flags ) ;
207223 file . persistentFile = this . persistentFiles . get ( path ) ;
208- await this . #requestAccessHandle( file ) ;
224+ await this . #requestAccessHandle( file . persistentFile ) ;
209225 } ) ( )
210226 ) ;
211227 return VFS . SQLITE_BUSY ;
@@ -282,7 +298,7 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
282298
283299 if ( file ?. flags & VFS . SQLITE_OPEN_MAIN_DB ) {
284300 if ( file . persistentFile ?. handleLockReleaser ) {
285- this . #releaseAccessHandle( file ) ;
301+ this . #releaseAccessHandle( file . persistentFile ) ;
286302 }
287303 } else if ( file ?. flags & VFS . SQLITE_OPEN_DELETEONCLOSE ) {
288304 file . accessHandle . truncate ( 0 ) ;
@@ -315,7 +331,7 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
315331 file . flags & VFS . SQLITE_OPEN_MAIN_DB &&
316332 ! file . persistentFile . isFileLocked
317333 ) {
318- this . #releaseAccessHandle( file ) ;
334+ this . #releaseAccessHandle( file . persistentFile ) ;
319335 }
320336
321337 if ( bytesRead < pData . byteLength ) {
@@ -408,12 +424,12 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
408424 file . persistentFile . isHandleRequested = true ;
409425 } else {
410426 // Release the access handles immediately.
411- this . #releaseAccessHandle( file ) ;
427+ this . #releaseAccessHandle( file . persistentFile ) ;
412428 }
413429 file . persistentFile . handleRequestChannel . onmessage = null ;
414430 } ;
415431
416- this . #requestAccessHandle( file ) ;
432+ this . #requestAccessHandle( file . persistentFile ) ;
417433 this . log ?.( 'returning SQLITE_BUSY' ) ;
418434 file . persistentFile . isLockBusy = true ;
419435 return VFS . SQLITE_BUSY ;
@@ -430,7 +446,7 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
430446 if ( ! file . persistentFile . isLockBusy ) {
431447 if ( file . persistentFile . isHandleRequested ) {
432448 // Another connection wants the access handle.
433- this . #releaseAccessHandle( file ) ;
449+ this . #releaseAccessHandle( file . persistentFile ) ;
434450 file . persistentFile . isHandleRequested = false ;
435451 }
436452 file . persistentFile . isFileLocked = false ;
@@ -490,10 +506,10 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
490506 async #createPersistentFile(
491507 fileHandle : FileSystemFileHandle
492508 ) : Promise < PersistentFile > {
493- const persistentFile = new PersistentFile ( fileHandle ) ;
494509 const root = await navigator . storage . getDirectory ( ) ;
495510 const relativePath = await root . resolve ( fileHandle ) ;
496511 const path = `/${ relativePath . join ( '/' ) } ` ;
512+ const persistentFile = new PersistentFile ( path , fileHandle ) ;
497513 persistentFile . handleRequestChannel = new BroadcastChannel ( `ahp:${ path } ` ) ;
498514 this . persistentFiles . set ( path , persistentFile ) ;
499515
@@ -504,52 +520,54 @@ export class OPFSCoopSyncVFS2 extends FacadeVFS {
504520 return persistentFile ;
505521 }
506522
507- #requestAccessHandle( file : File ) : Promise < void > {
508- console . assert ( ! file . persistentFile . handleLockReleaser ) ;
509- if ( ! file . persistentFile . isRequestInProgress ) {
510- file . persistentFile . isRequestInProgress = true ;
523+ #requestAccessHandle( persistentFile : PersistentFile ) : Promise < void > {
524+ console . assert ( ! persistentFile . handleLockReleaser ) ;
525+ if ( ! persistentFile . isRequestInProgress ) {
526+ persistentFile . isRequestInProgress = true ;
527+ this . log ?.( 'Requesting lock for' , persistentFile . path ) ;
511528 this . #module. retryOps . push (
512529 ( async ( ) => {
513530 // Acquire the Web Lock.
514- file . persistentFile . handleLockReleaser = await this . #acquireLock(
515- file . persistentFile
516- ) ;
531+ persistentFile . handleLockReleaser =
532+ await this . #acquireLock( persistentFile ) ;
517533
518534 // Get access handles for the database and releated files in parallel.
519- this . log ?.( `creating access handles for ${ file . path } ` ) ;
535+ this . log ?.( `creating access handles for ${ persistentFile . path } ` ) ;
520536 await Promise . all (
521537 DB_RELATED_FILE_SUFFIXES . map ( async ( suffix ) => {
522- const persistentFile = this . persistentFiles . get (
523- file . path + suffix
538+ const subPersistentFile = this . persistentFiles . get (
539+ persistentFile . path + suffix
524540 ) ;
525- if ( persistentFile ) {
526- persistentFile . accessHandle = await (
527- persistentFile . fileHandle as any
541+ if ( subPersistentFile ) {
542+ subPersistentFile . accessHandle = await (
543+ subPersistentFile . fileHandle as any
528544 ) . createSyncAccessHandle ( ) ;
529545 }
530546 } )
531547 ) ;
532- file . persistentFile . isRequestInProgress = false ;
548+ persistentFile . isRequestInProgress = false ;
533549 } ) ( )
534550 ) ;
535551 return this . #module. retryOps . at ( - 1 ) ;
536552 }
537553 return Promise . resolve ( ) ;
538554 }
539555
540- async #releaseAccessHandle( file : File ) : Promise < void > {
556+ async #releaseAccessHandle( persistentFile : PersistentFile ) : Promise < void > {
541557 DB_RELATED_FILE_SUFFIXES . forEach ( async ( suffix ) => {
542- const persistentFile = this . persistentFiles . get ( file . path + suffix ) ;
543- if ( persistentFile ) {
544- persistentFile . accessHandle ?. close ( ) ;
545- persistentFile . accessHandle = null ;
558+ const subPersistentFile = this . persistentFiles . get (
559+ persistentFile . path + suffix
560+ ) ;
561+ if ( subPersistentFile ) {
562+ subPersistentFile . accessHandle ?. close ( ) ;
563+ subPersistentFile . accessHandle = null ;
546564 }
547565 } ) ;
548- this . log ?.( `access handles closed for ${ file . path } ` ) ;
566+ this . log ?.( `access handles closed for ${ persistentFile . path } ` ) ;
549567
550- file . persistentFile . handleLockReleaser ?.( ) ;
551- file . persistentFile . handleLockReleaser = null ;
552- this . log ?.( `lock released for ${ file . path } ` ) ;
568+ persistentFile . handleLockReleaser ?.( ) ;
569+ persistentFile . handleLockReleaser = null ;
570+ this . log ?.( `lock released for ${ persistentFile . path } ` ) ;
553571 }
554572
555573 #acquireLock( persistentFile : PersistentFile ) : Promise < ( ) => void > {
0 commit comments