@@ -2,22 +2,17 @@ import { withErrno } from 'kerium';
2
2
import { alert , crit , err , warn } from 'kerium/log' ;
3
3
import { field , offsetof , packed , sizeof , struct , types as t , type StructArray } from 'memium' ;
4
4
import type { UUID } from 'node:crypto' ;
5
- import { randomInt } from 'utilium' ;
6
5
import { BufferView } from 'utilium/buffer.js' ;
7
6
import { crc32c } from 'utilium/checksum.js' ;
8
7
import { decodeUUID , encodeUUID } from 'utilium/string.js' ;
9
8
import type { UsageInfo } from '../internal/filesystem.js' ;
10
9
import { _inode_version , Inode } from '../internal/inode.js' ;
11
- import { size_max } from '../vfs/constants.js' ;
12
10
import type { Backend } from './backend.js' ;
13
11
import { StoreFS } from './store/fs.js' ;
14
12
import { SyncMapTransaction , type SyncMapStore } from './store/map.js' ;
15
13
import type { Store } from './store/store.js' ;
16
14
17
- interface Lock extends Disposable {
18
- nonce : number ;
19
- release ( ) : void ;
20
- }
15
+ type Lock = Disposable & ( ( ) => void ) ;
21
16
22
17
// eslint-disable-next-line @typescript-eslint/unbound-method
23
18
const { format } = new Intl . NumberFormat ( 'en-US' , {
@@ -41,7 +36,7 @@ class MetadataEntry extends BufferView {
41
36
/** The size of the data */
42
37
@t . uint32 accessor size ! : number ;
43
38
44
- toString ( long : boolean = false ) {
39
+ public toString ( long : boolean = false ) {
45
40
if ( ! long ) return `<MetadataEntry @ 0x${ this . byteOffset . toString ( 16 ) . padStart ( 8 , '0' ) } >` ;
46
41
47
42
return `0x${ this . id . toString ( 16 ) . padStart ( 8 , '0' ) } : ${ format ( this . size ) . padStart ( 5 ) } at 0x${ this . offset . toString ( 16 ) . padStart ( 8 , '0' ) } ` ;
@@ -126,39 +121,34 @@ export class MetadataBlock extends Int32Array<ArrayBufferLike> {
126
121
if ( depth > max_lock_attempts )
127
122
throw crit ( withErrno ( 'EBUSY' , `sbfs: exceeded max attempts waiting for metadata block at ${ this . offsetHex } to be unlocked` ) ) ;
128
123
129
- const i = offsetof ( this , 'locked' ) ;
130
- if ( Atomics . load ( this , i ) !== 0 ) {
131
- switch ( Atomics . wait ( this , i , 0 ) ) {
132
- case 'ok' :
133
- break ;
134
- case 'not-equal' :
135
- depth ++ ;
136
- err ( `sbfs: waiting for metadata block at ${ this . offsetHex } to be unlocked (${ depth } /${ max_lock_attempts } )` ) ;
137
- return this . waitUnlocked ( depth ) ;
138
- case 'timed-out' :
139
- throw crit ( withErrno ( 'EBUSY' , `sbfs: timed out waiting for metadata block at ${ this . offsetHex } to be unlocked` ) ) ;
140
- }
124
+ const i = this . length - 1 ;
125
+ if ( ! Atomics . load ( this , i ) ) return ;
126
+ switch ( Atomics . wait ( this , i , 1 ) ) {
127
+ case 'ok' :
128
+ break ;
129
+ case 'not-equal' :
130
+ depth ++ ;
131
+ err ( `sbfs: waiting for metadata block at ${ this . offsetHex } to be unlocked (${ depth } /${ max_lock_attempts } )` ) ;
132
+ return this . waitUnlocked ( depth ) ;
133
+ case 'timed-out' :
134
+ throw crit ( withErrno ( 'EBUSY' , `sbfs: timed out waiting for metadata block at ${ this . offsetHex } to be unlocked` ) ) ;
141
135
}
142
136
}
143
137
144
- public lock ( nonce : number = randomInt ( 1 , size_max / 2 ) ) : Lock {
138
+ public lock ( ) : Lock {
145
139
this . waitUnlocked ( ) ;
146
140
147
141
const i = offsetof ( this , 'locked' ) ;
148
- Atomics . store ( this , i , nonce ) ;
142
+ Atomics . store ( this , i , 1 ) ;
149
143
150
144
const release = ( ) => {
151
145
Atomics . store ( this , i , 0 ) ;
152
146
Atomics . notify ( this , i , 1 ) ;
153
147
} ;
154
148
155
- return {
156
- nonce,
157
- release,
158
- [ Symbol . dispose ] ( ) {
159
- release ( ) ;
160
- } ,
161
- } ;
149
+ release [ Symbol . dispose ] = release ;
150
+
151
+ return release ;
162
152
}
163
153
}
164
154
@@ -193,11 +183,11 @@ export class SuperBlock extends BufferView {
193
183
return ;
194
184
}
195
185
196
- if ( ! checksumMatches ( this ) ) throw crit ( withErrno ( 'EIO' , 'sbfs: checksum mismatch for super block' ) ) ;
186
+ if ( this . checksum !== checksum ( this ) ) throw crit ( withErrno ( 'EIO' , 'sbfs: checksum mismatch for super block' ) ) ;
197
187
198
188
this . metadata = new MetadataBlock ( this . buffer , this . metadata_offset ) ;
199
189
200
- if ( ! checksumMatches ( this . metadata ) )
190
+ if ( this . metadata . checksum !== checksum ( this . metadata ) )
201
191
throw crit (
202
192
withErrno (
203
193
'EIO' ,
@@ -310,16 +300,11 @@ export class SuperBlock extends BufferView {
310
300
* Note we don't include the checksum when computing a new one.
311
301
*/
312
302
function checksum ( value : SuperBlock | MetadataBlock ) : number {
313
- const buffer = new Uint8Array ( value . buffer , value . byteOffset + 4 , sizeof ( value ) - 4 ) ;
314
- return crc32c ( buffer ) ;
315
- }
316
-
317
- function checksumMatches ( value : SuperBlock | MetadataBlock ) : boolean {
318
- return value . checksum === checksum ( value ) ;
303
+ return crc32c ( new Uint8Array ( value . buffer , value . byteOffset + 4 , sizeof ( value ) - 4 ) ) ;
319
304
}
320
305
321
306
/**
322
- * Update a block's checksum and write it to the store's buffer .
307
+ * Update a block's checksum and timestamp .
323
308
* @internal @hidden
324
309
*/
325
310
function _update ( value : SuperBlock | MetadataBlock ) : void {
@@ -360,22 +345,25 @@ export class SingleBufferStore extends BufferView implements SyncMapStore {
360
345
this . superblock = new SuperBlock ( this . buffer , this . byteOffset ) ;
361
346
}
362
347
363
- public keys ( ) : Iterable < number > {
348
+ public * keys ( ) : Iterable < number > {
364
349
const keys = new Set < number > ( ) ;
365
350
for ( let block : MetadataBlock | undefined = this . superblock . metadata ; block ; block = block . previous ) {
366
351
block . waitUnlocked ( ) ;
367
- for ( const entry of block . items ) if ( entry . offset ) keys . add ( entry . id ) ;
352
+ for ( const entry of block . items ) {
353
+ if ( ! entry . offset || keys . has ( entry . id ) ) continue ;
354
+ keys . add ( entry . id ) ;
355
+ yield entry . id ;
356
+ }
368
357
}
369
- return keys ;
370
358
}
371
359
372
360
public get ( id : number ) : Uint8Array | undefined {
373
361
for ( let block : MetadataBlock | undefined = this . superblock . metadata ; block ; block = block . previous ) {
374
362
block . waitUnlocked ( ) ;
375
363
for ( const entry of block . items ) {
376
- if ( entry . offset && entry . id == id ) {
377
- return new Uint8Array ( this . buffer , entry . offset , entry . size ) ;
378
- }
364
+ if ( ! entry . offset || entry . id != id ) continue ;
365
+ const off = this . byteOffset + entry . offset ;
366
+ return new Uint8Array ( this . buffer . slice ( off , off + entry . size ) ) ;
379
367
}
380
368
}
381
369
}
@@ -390,29 +378,21 @@ export class SingleBufferStore extends BufferView implements SyncMapStore {
390
378
391
379
using lock = block . lock ( ) ;
392
380
393
- const _write = ( ) => {
394
- for ( let i = 0 ; i < data . length ; i ++ ) this . _u8 [ entry . offset + i ] = data [ i ] ;
395
- } ;
396
-
397
- if ( data . length <= entry . size ) {
398
- _write ( ) ;
399
- if ( data . length < entry . size ) {
400
- entry . size = data . length ;
401
- _update ( block ) ;
402
- }
381
+ if ( data . length == entry . size ) {
382
+ this . _u8 . set ( data , entry . offset ) ;
403
383
return ;
404
384
}
405
385
406
- if ( this . superblock . isUnused ( entry . offset , data . length ) ) {
386
+ if ( data . length < entry . size || this . superblock . isUnused ( entry . offset , data . length ) ) {
387
+ this . _u8 . set ( data , entry . offset ) ;
407
388
entry . size = data . length ;
408
- _write ( ) ;
409
389
_update ( block ) ;
410
390
return ;
411
391
}
412
392
413
393
entry . offset = Number ( this . superblock . used_bytes ) ;
414
394
entry . size = data . length ;
415
- _write ( ) ;
395
+ this . _u8 . set ( data , entry . offset ) ;
416
396
_update ( block ) ;
417
397
this . superblock . used_bytes += BigInt ( data . length ) ;
418
398
_update ( this . superblock ) ;
@@ -435,7 +415,7 @@ export class SingleBufferStore extends BufferView implements SyncMapStore {
435
415
entry . offset = offset ;
436
416
entry . size = data . length ;
437
417
438
- for ( let i = 0 ; i < data . length ; i ++ ) this . _u8 [ offset + i ] = data [ i ] ;
418
+ this . _u8 . set ( data , offset ) ;
439
419
440
420
this . superblock . used_bytes += BigInt ( data . length ) ;
441
421
_update ( this . superblock . metadata ) ;
@@ -449,6 +429,7 @@ export class SingleBufferStore extends BufferView implements SyncMapStore {
449
429
if ( entry . id != id ) continue ;
450
430
entry . offset = 0 ;
451
431
entry . size = 0 ;
432
+ entry . id = 0 ;
452
433
_update ( block ) ;
453
434
return ;
454
435
}
0 commit comments