@@ -53,6 +53,8 @@ class LogFileManager {
53
53
54
54
readonly #onDiskFileSizeInBytes: number ;
55
55
56
+ readonly #onExportChunk: ( logs : string ) => void ;
57
+
56
58
readonly #onQueryResults: ( queryProgress : number , queryResults : QueryResults ) => void ;
57
59
58
60
#decoder: Decoder ;
@@ -68,19 +70,29 @@ class LogFileManager {
68
70
* @param params.fileName
69
71
* @param params.onDiskFileSizeInBytes
70
72
* @param params.pageSize Page size for setting up pagination.
73
+ * @param params.onExportChunk
71
74
* @param params.onQueryResults
72
75
*/
73
- constructor ( { decoder, fileName, onDiskFileSizeInBytes, pageSize, onQueryResults} : {
76
+ constructor ( {
77
+ decoder,
78
+ fileName,
79
+ onDiskFileSizeInBytes,
80
+ pageSize,
81
+ onExportChunk,
82
+ onQueryResults,
83
+ } : {
74
84
decoder : Decoder ;
75
85
fileName : string ;
76
86
onDiskFileSizeInBytes : number ;
77
87
pageSize : number ;
88
+ onExportChunk : ( logs : string ) => void ;
78
89
onQueryResults : ( queryProgress : number , queryResults : QueryResults ) => void ;
79
90
} ) {
80
91
this . #decoder = decoder ;
81
92
this . #fileName = fileName ;
82
93
this . #pageSize = pageSize ;
83
94
this . #onDiskFileSizeInBytes = onDiskFileSizeInBytes ;
95
+ this . #onExportChunk = onExportChunk ;
84
96
this . #onQueryResults = onQueryResults ;
85
97
86
98
// Build index for the entire file.
@@ -108,19 +120,28 @@ class LogFileManager {
108
120
/**
109
121
* Creates a new LogFileManager.
110
122
*
111
- * @param fileSrc The source of the file to load. This can be a string representing a URL, or a
112
- * File object.
113
- * @param pageSize Page size for setting up pagination.
114
- * @param decoderOptions Initial decoder options.
115
- * @param onQueryResults
123
+ * @param params
124
+ * @param params.fileSrc The source of the file to load.
125
+ * This can be a string representing a URL, or a File object.
126
+ * @param params.pageSize Page size for setting up pagination.
127
+ * @param params.decoderOptions Initial decoder options.
128
+ * @param params.onExportChunk
129
+ * @param params.onQueryResults
116
130
* @return A Promise that resolves to the created LogFileManager instance.
117
131
*/
118
- static async create (
119
- fileSrc : FileSrcType ,
120
- pageSize : number ,
121
- decoderOptions : DecoderOptions ,
122
- onQueryResults : ( queryProgress : number , queryResults : QueryResults ) => void ,
123
- ) : Promise < LogFileManager > {
132
+ static async create ( {
133
+ fileSrc,
134
+ pageSize,
135
+ decoderOptions,
136
+ onExportChunk,
137
+ onQueryResults,
138
+ } : {
139
+ fileSrc : FileSrcType ;
140
+ pageSize : number ;
141
+ decoderOptions : DecoderOptions ;
142
+ onExportChunk : ( logs : string ) => void ;
143
+ onQueryResults : ( queryProgress : number , queryResults : QueryResults ) => void ;
144
+ } ) : Promise < LogFileManager > {
124
145
const { fileName, fileData} = await loadFile ( fileSrc ) ;
125
146
const decoder = await LogFileManager . #initDecoder( fileName , fileData , decoderOptions ) ;
126
147
@@ -130,6 +151,7 @@ class LogFileManager {
130
151
onDiskFileSizeInBytes : fileData . length ,
131
152
pageSize : pageSize ,
132
153
154
+ onExportChunk : onExportChunk ,
133
155
onQueryResults : onQueryResults ,
134
156
} ) ;
135
157
}
@@ -187,17 +209,13 @@ class LogFileManager {
187
209
}
188
210
189
211
/**
190
- * Loads log events in the range
191
- * [`beginLogEventIdx`, `beginLogEventIdx + EXPORT_LOGS_CHUNK_SIZE`), or all remaining log
192
- * events if `EXPORT_LOGS_CHUNK_SIZE` log events aren't available.
212
+ * Exports a chunk of log events, sends the results to the renderer, and schedules the next
213
+ * chunk if more log events remain.
193
214
*
194
215
* @param beginLogEventIdx
195
- * @return An object containing the log events as a string.
196
216
* @throws {Error } if any error occurs when decoding the log events.
197
217
*/
198
- loadChunk ( beginLogEventIdx : number ) : {
199
- logs : string ;
200
- } {
218
+ exportChunkAndScheduleNext ( beginLogEventIdx : number ) {
201
219
const endLogEventIdx = Math . min ( beginLogEventIdx + EXPORT_LOGS_CHUNK_SIZE , this . #numEvents) ;
202
220
const results = this . #decoder. decodeRange (
203
221
beginLogEventIdx ,
@@ -212,10 +230,13 @@ class LogFileManager {
212
230
}
213
231
214
232
const messages = results . map ( ( [ msg ] ) => msg ) ;
233
+ this . #onExportChunk( messages . join ( "" ) ) ;
215
234
216
- return {
217
- logs : messages . join ( "" ) ,
218
- } ;
235
+ if ( endLogEventIdx < this . #numEvents) {
236
+ defer ( ( ) => {
237
+ this . exportChunkAndScheduleNext ( endLogEventIdx ) ;
238
+ } ) ;
239
+ }
219
240
}
220
241
221
242
/**
@@ -327,45 +348,6 @@ class LogFileManager {
327
348
}
328
349
}
329
350
330
- /**
331
- * Processes decoded log events and populates the results map with matched entries.
332
- *
333
- * @param decodedEvents
334
- * @param queryRegex
335
- * @param results The map to store query results.
336
- */
337
- #processQueryDecodedEvents (
338
- decodedEvents : DecodeResult [ ] ,
339
- queryRegex : RegExp ,
340
- results : QueryResults
341
- ) : void {
342
- for ( const [ message , , , logEventNum ] of decodedEvents ) {
343
- const matchResult = message . match ( queryRegex ) ;
344
- if ( null === matchResult || "number" !== typeof matchResult . index ) {
345
- continue ;
346
- }
347
-
348
- const pageNum = Math . ceil ( logEventNum / this . #pageSize) ;
349
- if ( false === results . has ( pageNum ) ) {
350
- results . set ( pageNum , [ ] ) ;
351
- }
352
-
353
- results . get ( pageNum ) ?. push ( {
354
- logEventNum : logEventNum ,
355
- message : message ,
356
- matchRange : [
357
- matchResult . index ,
358
- matchResult . index + matchResult [ 0 ] . length ,
359
- ] ,
360
- } ) ;
361
-
362
- this . #queryCount++ ;
363
- if ( this . #queryCount >= MAX_QUERY_RESULT_COUNT ) {
364
- break ;
365
- }
366
- }
367
- }
368
-
369
351
/**
370
352
* Queries a chunk of log events, sends the results, and schedules the next chunk query if more
371
353
* log events remain.
@@ -423,6 +405,45 @@ class LogFileManager {
423
405
}
424
406
}
425
407
408
+ /**
409
+ * Processes decoded log events and populates the results map with matched entries.
410
+ *
411
+ * @param decodedEvents
412
+ * @param queryRegex
413
+ * @param results The map to store query results.
414
+ */
415
+ #processQueryDecodedEvents (
416
+ decodedEvents : DecodeResult [ ] ,
417
+ queryRegex : RegExp ,
418
+ results : QueryResults
419
+ ) : void {
420
+ for ( const [ message , , , logEventNum ] of decodedEvents ) {
421
+ const matchResult = message . match ( queryRegex ) ;
422
+ if ( null === matchResult || "number" !== typeof matchResult . index ) {
423
+ continue ;
424
+ }
425
+
426
+ const pageNum = Math . ceil ( logEventNum / this . #pageSize) ;
427
+ if ( false === results . has ( pageNum ) ) {
428
+ results . set ( pageNum , [ ] ) ;
429
+ }
430
+
431
+ results . get ( pageNum ) ?. push ( {
432
+ logEventNum : logEventNum ,
433
+ message : message ,
434
+ matchRange : [
435
+ matchResult . index ,
436
+ matchResult . index + matchResult [ 0 ] . length ,
437
+ ] ,
438
+ } ) ;
439
+
440
+ this . #queryCount++ ;
441
+ if ( this . #queryCount >= MAX_QUERY_RESULT_COUNT ) {
442
+ break ;
443
+ }
444
+ }
445
+ }
446
+
426
447
/**
427
448
* Gets the data that corresponds to the cursor.
428
449
*
0 commit comments