@@ -22,13 +22,13 @@ const { details: X } = assert;
22
22
23
23
export const DEFAULT_CIRCULAR_BUFFER_SIZE = 100 * 1024 * 1024 ;
24
24
export const DEFAULT_CIRCULAR_BUFFER_FILE = 'flight-recorder.bin' ;
25
- export const SLOG_MAGIC = 0x21474f4c532d4741n ; // 'AG-SLOG!'
25
+ export const SLOG_MAGIC = 0x41472d534c4f4721n ; // 'AG-SLOG!'
26
26
27
- const I_MAGIC = 0 ;
28
- const I_ARENA_SIZE = 1 ;
29
- const I_CIRC_START = 2 ;
30
- const I_CIRC_END = 3 ;
31
- const HEADER_LENGTH = 4 ;
27
+ const I_MAGIC = 0 * BigUint64Array . BYTES_PER_ELEMENT ;
28
+ const I_ARENA_SIZE = 1 * BigUint64Array . BYTES_PER_ELEMENT ;
29
+ const I_CIRC_START = 2 * BigUint64Array . BYTES_PER_ELEMENT ;
30
+ const I_CIRC_END = 3 * BigUint64Array . BYTES_PER_ELEMENT ;
31
+ const I_ARENA_START = 4 * BigUint64Array . BYTES_PER_ELEMENT ;
32
32
33
33
const initializeCircularBuffer = async ( bufferFile , circularBufferSize ) => {
34
34
if ( ! circularBufferSize ) {
@@ -41,25 +41,24 @@ const initializeCircularBuffer = async (bufferFile, circularBufferSize) => {
41
41
}
42
42
throw e ;
43
43
} ) ;
44
- const arenaSize = BigInt (
45
- circularBufferSize - HEADER_LENGTH * BigUint64Array . BYTES_PER_ELEMENT ,
46
- ) ;
44
+ const arenaSize = BigInt ( circularBufferSize - I_ARENA_START ) ;
47
45
48
46
const writeHeader = async ( ) => {
49
- if (
50
- stbuf &&
51
- stbuf . size >= HEADER_LENGTH * BigUint64Array . BYTES_PER_ELEMENT
52
- ) {
47
+ if ( stbuf && stbuf . size >= I_ARENA_START ) {
53
48
// Header already exists.
54
49
return ;
55
50
}
56
51
57
52
// Write the header.
58
- const header = new Array ( HEADER_LENGTH ) . fill ( 0n ) ;
59
- header [ I_MAGIC ] = SLOG_MAGIC ;
60
- header [ I_ARENA_SIZE ] = arenaSize ;
53
+ const headerBuf = new Uint8Array ( I_ARENA_START ) ;
54
+ const header = new DataView ( headerBuf . buffer ) ;
55
+ header . setBigUint64 ( I_MAGIC , SLOG_MAGIC ) ;
56
+ header . setBigUint64 ( I_ARENA_SIZE , arenaSize ) ;
57
+ header . setBigUint64 ( I_CIRC_START , 0n ) ;
58
+ header . setBigUint64 ( I_CIRC_END , 0n ) ;
59
+
61
60
await fsPromises . mkdir ( path . dirname ( bufferFile ) , { recursive : true } ) ;
62
- await fsPromises . writeFile ( bufferFile , BigUint64Array . from ( header ) ) ;
61
+ await fsPromises . writeFile ( bufferFile , headerBuf ) ;
63
62
} ;
64
63
await writeHeader ( ) ;
65
64
@@ -92,20 +91,22 @@ export const makeMemoryMappedCircularBuffer = async ({
92
91
93
92
/** @type {Uint8Array } */
94
93
const fileBuf = BufferFromFile ( bufferFile ) . Uint8Array ( ) ;
95
- const header = new BigUint64Array ( fileBuf . buffer , 0 , HEADER_LENGTH ) ;
94
+ const header = new DataView ( fileBuf . buffer , 0 , I_ARENA_START ) ;
96
95
97
96
// Detect the arena size from the header, if not initialized.
98
- const arenaSize = newArenaSize || header [ I_ARENA_SIZE ] ;
97
+ const hdrArenaSize = header . getBigUint64 ( I_ARENA_SIZE ) ;
98
+ const arenaSize = newArenaSize || hdrArenaSize ;
99
99
100
+ const hdrMagic = header . getBigUint64 ( I_MAGIC ) ;
100
101
assert . equal (
101
102
SLOG_MAGIC ,
102
- header [ I_MAGIC ] ,
103
- X `${ bufferFile } is not a slog buffer; wanted magic ${ SLOG_MAGIC } , got ${ header [ I_MAGIC ] } ` ,
103
+ hdrMagic ,
104
+ X `${ bufferFile } is not a slog buffer; wanted magic ${ SLOG_MAGIC } , got ${ hdrMagic } ` ,
104
105
) ;
105
106
assert . equal (
106
107
arenaSize ,
107
- header [ I_ARENA_SIZE ] ,
108
- X `${ bufferFile } arena size mismatch; wanted ${ arenaSize } , got ${ header [ I_ARENA_SIZE ] } ` ,
108
+ hdrArenaSize ,
109
+ X `${ bufferFile } arena size mismatch; wanted ${ arenaSize } , got ${ hdrArenaSize } ` ,
109
110
) ;
110
111
const arena = new Uint8Array (
111
112
fileBuf . buffer ,
@@ -126,21 +127,19 @@ export const makeMemoryMappedCircularBuffer = async ({
126
127
127
128
// Read the data to the end of the arena.
128
129
let firstReadLength = data . byteLength ;
129
- const circStart = Number ( header [ I_CIRC_START ] ) ;
130
- const readStart = ( circStart + offset ) % Number ( arenaSize ) ;
131
- if ( header [ I_CIRC_START ] > header [ I_CIRC_END ] ) {
130
+ const circStart = header . getBigUint64 ( I_CIRC_START ) ;
131
+ const circEnd = header . getBigUint64 ( I_CIRC_END ) ;
132
+ const readStart = ( Number ( circStart ) + offset ) % Number ( arenaSize ) ;
133
+ if ( circStart > circEnd ) {
132
134
// The data is wrapped around the end of the arena, like BBB---AAA
133
135
firstReadLength = Math . min (
134
136
firstReadLength ,
135
137
Number ( arenaSize ) - readStart ,
136
138
) ;
137
- if ( readStart >= header [ I_CIRC_END ] && readStart < header [ I_CIRC_START ] ) {
139
+ if ( readStart >= circEnd && readStart < circStart ) {
138
140
return { done : true , value : undefined } ;
139
141
}
140
- } else if (
141
- readStart < header [ I_CIRC_START ] ||
142
- readStart >= header [ I_CIRC_END ]
143
- ) {
142
+ } else if ( readStart < circStart || readStart >= circEnd ) {
144
143
// The data is contiguous, like ---AAABBB---
145
144
return { done : true , value : undefined } ;
146
145
}
@@ -168,58 +167,64 @@ export const makeMemoryMappedCircularBuffer = async ({
168
167
const record = new Uint8Array (
169
168
BigUint64Array . BYTES_PER_ELEMENT + data . byteLength ,
170
169
) ;
171
- const lengthPrefix = new BigUint64Array ( record . buffer , 0 , 1 ) ;
172
- lengthPrefix [ 0 ] = BigInt ( data . byteLength ) ;
173
170
record . set ( data , BigUint64Array . BYTES_PER_ELEMENT ) ;
174
171
172
+ const lengthPrefix = new DataView ( record . buffer ) ;
173
+ lengthPrefix . setBigUint64 ( 0 , BigInt ( data . byteLength ) ) ;
174
+
175
175
// Check if we need to wrap around.
176
176
/** @type {bigint } */
177
177
let capacity ;
178
- if ( header [ I_CIRC_START ] <= header [ I_CIRC_END ] ) {
178
+ let circStart = header . getBigUint64 ( I_CIRC_START ) ;
179
+ const circEnd = header . getBigUint64 ( I_CIRC_END ) ;
180
+ if ( circStart <= circEnd ) {
179
181
// ---AAAABBBB----
180
- capacity =
181
- header [ I_ARENA_SIZE ] - header [ I_CIRC_END ] + header [ I_CIRC_START ] ;
182
+ capacity = arenaSize - circEnd + circStart ;
182
183
} else {
183
184
// BBB---AAAA
184
- capacity = header [ I_CIRC_START ] - header [ I_CIRC_END ] ;
185
+ capacity = circStart - circEnd ;
185
186
}
186
187
187
188
// Advance the start pointer until we have space to write the record.
188
189
let overlap = BigInt ( record . byteLength ) - capacity ;
189
190
while ( overlap > 0n ) {
190
- const startRecordLength = new BigUint64Array ( 1 ) ;
191
- const { done } = readCircBuf ( new Uint8Array ( startRecordLength . buffer ) ) ;
191
+ const startRecordLength = new Uint8Array (
192
+ BigUint64Array . BYTES_PER_ELEMENT ,
193
+ ) ;
194
+ const { done } = readCircBuf ( startRecordLength ) ;
192
195
if ( done ) {
193
196
break ;
194
197
}
195
198
199
+ const dv = new DataView ( startRecordLength . buffer ) ;
196
200
const totalRecordLength =
197
201
BigInt ( startRecordLength . byteLength ) + // size of the length field
198
- startRecordLength [ 0 ] ; // size of the record
202
+ dv . getBigUint64 ( 0 ) ; // size of the record
199
203
200
- header [ I_CIRC_START ] =
201
- ( header [ I_CIRC_START ] + totalRecordLength ) % header [ I_ARENA_SIZE ] ;
204
+ circStart = ( circStart + totalRecordLength ) % arenaSize ;
205
+ header . setBigUint64 ( I_CIRC_START , circStart ) ;
202
206
overlap -= totalRecordLength ;
203
207
}
204
208
205
209
// Append the record.
206
210
let firstWriteLength = record . byteLength ;
207
- if ( header [ I_CIRC_START ] < header [ I_CIRC_END ] ) {
211
+ if ( circStart < circEnd ) {
208
212
// May need to wrap, it's ---AAAABBBB---
209
213
firstWriteLength = Math . min (
210
214
firstWriteLength ,
211
- Number ( header [ I_ARENA_SIZE ] - header [ I_CIRC_END ] ) ,
215
+ Number ( arenaSize - circEnd ) ,
212
216
) ;
213
217
}
214
218
215
- const circEnd = Number ( header [ I_CIRC_END ] ) ;
216
- arena . set ( record . subarray ( 0 , firstWriteLength ) , circEnd ) ;
219
+ arena . set ( record . subarray ( 0 , firstWriteLength ) , Number ( circEnd ) ) ;
217
220
if ( firstWriteLength < record . byteLength ) {
218
221
// Write to the beginning of the arena.
219
222
arena . set ( record . subarray ( firstWriteLength , record . byteLength ) , 0 ) ;
220
223
}
221
- header [ I_CIRC_END ] =
222
- ( header [ I_CIRC_END ] + BigInt ( record . byteLength ) ) % header [ I_ARENA_SIZE ] ;
224
+ header . setBigUint64 (
225
+ I_CIRC_END ,
226
+ ( circEnd + BigInt ( record . byteLength ) ) % arenaSize ,
227
+ ) ;
223
228
} ;
224
229
225
230
const writeJSON = ( obj , jsonObj ) => {
@@ -231,7 +236,7 @@ export const makeMemoryMappedCircularBuffer = async ({
231
236
}
232
237
// Prepend a newline so that the file can be more easily manipulated.
233
238
const data = new TextEncoder ( ) . encode ( `\n${ jsonObj } ` ) ;
234
- // console.log('have obj', obj);
239
+ // console.log('have obj', obj, data );
235
240
writeCircBuf ( data ) ;
236
241
} ;
237
242
0 commit comments