readline-pager 0.5.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -5
- package/dist/main.cjs +179 -193
- package/dist/main.d.cts +2 -2
- package/dist/main.d.mts +2 -2
- package/dist/main.mjs +179 -193
- package/dist/{native-46pCT8Rc.d.cts → native-DGzYrMHK.d.mts} +17 -6
- package/dist/{native-DeBXdY3U.d.mts → native-_NmVYcF6.d.cts} +17 -6
- package/dist/native.cjs +7 -8
- package/dist/native.d.cts +1 -1
- package/dist/native.d.mts +1 -1
- package/dist/native.mjs +7 -8
- package/dist/worker.cjs +40 -28
- package/dist/worker.mjs +40 -28
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
- 🔁 Async (`for await...of`) and sync (`for...of`) iteration
|
|
21
21
|
- 📄 Page-based reading with manual control (`next`, `nextSync`)
|
|
22
22
|
- 🔀 Forward and backward reading support
|
|
23
|
-
- 🧪 Fully typed with high test coverage (
|
|
23
|
+
- 🧪 Fully typed with high test coverage (>90%)
|
|
24
24
|
|
|
25
25
|
> **Important:**
|
|
26
26
|
> Performance depends heavily on the `chunkSize` option. Tune it for your storage device. A value of **64 KiB** is usually a good starting point. Increasing it may improve throughput until you reach the best value for your hardware.
|
|
@@ -68,7 +68,7 @@ let page;
|
|
|
68
68
|
const pager = createPager("./bigfile.txt");
|
|
69
69
|
while ((page = pager.nextSync()) !== null) {}
|
|
70
70
|
|
|
71
|
-
// Native C++
|
|
71
|
+
// Native C++
|
|
72
72
|
for await (const page of createNativePager("./bigfile.txt")) {
|
|
73
73
|
}
|
|
74
74
|
```
|
|
@@ -87,6 +87,12 @@ createPager(filepath, {
|
|
|
87
87
|
useWorker?: boolean, // default: false
|
|
88
88
|
tryNative?: boolean, // default: true
|
|
89
89
|
});
|
|
90
|
+
|
|
91
|
+
createNativePager(filepath, {
|
|
92
|
+
pageSize?: number, // default: 1_000
|
|
93
|
+
delimiter?: string, // default: "\n"
|
|
94
|
+
backward?: boolean, // default: false
|
|
95
|
+
});
|
|
90
96
|
```
|
|
91
97
|
|
|
92
98
|
- `chunkSize` — number of bytes read per I/O operation.
|
|
@@ -98,7 +104,7 @@ createPager(filepath, {
|
|
|
98
104
|
- `tryNative` — attempts to use the native reader, falls back to the non-native version if it fails.
|
|
99
105
|
|
|
100
106
|
> **Note:**
|
|
101
|
-
> `createNativePager`
|
|
107
|
+
> `createNativePager` requires x86 AVX2 or ARM NEON CPU instruction set extensions and will throw if they are not available. It also does **not** support multi-character delimiters due to fast SIMD-based scanning.
|
|
102
108
|
|
|
103
109
|
---
|
|
104
110
|
|
|
@@ -138,7 +144,7 @@ Run the benchmark locally:
|
|
|
138
144
|
npm run benchmark:node
|
|
139
145
|
|
|
140
146
|
# or customize with args
|
|
141
|
-
node test/
|
|
147
|
+
node test/benchmark.ts --lines=20000 --page-size=500 --backward
|
|
142
148
|
```
|
|
143
149
|
|
|
144
150
|
> Test setup: generated text files (UUID lines), NVMe SSD, Node.js runtime.
|
|
@@ -164,7 +170,7 @@ node test/_benchmark.ts --lines=20000 --page-size=500 --backward
|
|
|
164
170
|
Run tests:
|
|
165
171
|
|
|
166
172
|
```bash
|
|
167
|
-
npm
|
|
173
|
+
npm i
|
|
168
174
|
npm test
|
|
169
175
|
```
|
|
170
176
|
|
package/dist/main.cjs
CHANGED
|
@@ -6,7 +6,7 @@ const require_native = require("./native.cjs");
|
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_fs_promises = require("node:fs/promises");
|
|
8
8
|
let node_worker_threads = require("node:worker_threads");
|
|
9
|
-
//#region src/
|
|
9
|
+
//#region src/helper.ts
|
|
10
10
|
function createRingBuffer(capacity) {
|
|
11
11
|
if (!Number.isFinite(capacity) || capacity <= 0) throw new RangeError("capacity must be a positive number");
|
|
12
12
|
let buf = new Array(capacity);
|
|
@@ -102,115 +102,99 @@ function createBackwardReader(filepath, options) {
|
|
|
102
102
|
let buffer = "";
|
|
103
103
|
let done = false;
|
|
104
104
|
let closed = false;
|
|
105
|
+
let flushed = false;
|
|
105
106
|
let startsWithDelimiter = false;
|
|
107
|
+
function consumeBuffer() {
|
|
108
|
+
let idx;
|
|
109
|
+
while ((idx = buffer.lastIndexOf(delimiter)) !== -1) {
|
|
110
|
+
const line = buffer.slice(idx + delimiter.length);
|
|
111
|
+
buffer = buffer.slice(0, idx);
|
|
112
|
+
local.push(line);
|
|
113
|
+
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function flushTail() {
|
|
117
|
+
if (flushed) return;
|
|
118
|
+
flushed = true;
|
|
119
|
+
if (buffer.length > 0) local.push(buffer);
|
|
120
|
+
else if (startsWithDelimiter) local.push("");
|
|
121
|
+
buffer = "";
|
|
122
|
+
while (local.length > 0) {
|
|
123
|
+
const page = local.slice(local.length - Math.min(pageSize, local.length));
|
|
124
|
+
local.length -= page.length;
|
|
125
|
+
pageQueue.push(page);
|
|
126
|
+
}
|
|
127
|
+
done = true;
|
|
128
|
+
pageQueue.wake();
|
|
129
|
+
}
|
|
106
130
|
fdSync = (0, node_fs.openSync)(filepath, "r");
|
|
107
131
|
pos = (0, node_fs.statSync)(filepath).size;
|
|
108
132
|
if (pos === 0) {
|
|
109
|
-
pageQueue.push([
|
|
133
|
+
pageQueue.push([""]);
|
|
110
134
|
done = true;
|
|
135
|
+
flushed = true;
|
|
111
136
|
pageQueue.wake();
|
|
112
137
|
}
|
|
113
138
|
(async () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
if (fd) {
|
|
123
|
-
await fd.close();
|
|
124
|
-
fd = null;
|
|
125
|
-
}
|
|
126
|
-
pageQueue.wake();
|
|
127
|
-
return;
|
|
139
|
+
fd = await (0, node_fs_promises.open)(filepath, "r");
|
|
140
|
+
pos = (await fd.stat()).size;
|
|
141
|
+
if (pos === 0) {
|
|
142
|
+
if (!done) {
|
|
143
|
+
pageQueue.push([""]);
|
|
144
|
+
done = true;
|
|
145
|
+
flushed = true;
|
|
128
146
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
await fd.read(buf, 0, readSize, pos);
|
|
135
|
-
buffer = buf.toString("utf8") + buffer;
|
|
136
|
-
if (pos === 0 && buffer.startsWith(delimiter)) startsWithDelimiter = true;
|
|
137
|
-
let idx;
|
|
138
|
-
while ((idx = buffer.lastIndexOf(delimiter)) !== -1) {
|
|
139
|
-
const line = buffer.slice(idx + delimiter.length);
|
|
140
|
-
buffer = buffer.slice(0, idx);
|
|
141
|
-
local.push(line);
|
|
142
|
-
while (local.length >= pageSize) {
|
|
143
|
-
const page = local.splice(0, pageSize);
|
|
144
|
-
pageQueue.push(page);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (pos === 0 && !done) {
|
|
149
|
-
if (buffer.length > 0) local.push(buffer);
|
|
150
|
-
else if (startsWithDelimiter) local.push("");
|
|
151
|
-
buffer = "";
|
|
152
|
-
while (local.length > 0 && !closed) {
|
|
153
|
-
const page = local.slice(local.length - Math.min(pageSize, local.length));
|
|
154
|
-
local.length -= page.length;
|
|
155
|
-
pageQueue.push(page);
|
|
156
|
-
}
|
|
157
|
-
done = true;
|
|
158
|
-
if (fd) {
|
|
159
|
-
await fd.close();
|
|
160
|
-
fd = null;
|
|
161
|
-
}
|
|
162
|
-
pageQueue.wake();
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
147
|
+
if (fd) {
|
|
148
|
+
try {
|
|
149
|
+
await fd.close();
|
|
150
|
+
} catch {}
|
|
151
|
+
fd = null;
|
|
166
152
|
}
|
|
167
|
-
} catch {
|
|
168
|
-
done = true;
|
|
169
153
|
pageQueue.wake();
|
|
170
|
-
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
while (!done && !closed) {
|
|
157
|
+
while (pageQueue.count < prefetch && pos > 0 && !closed) {
|
|
158
|
+
const readSize = Math.min(chunkSize, pos);
|
|
159
|
+
pos -= readSize;
|
|
160
|
+
const buf = Buffer.allocUnsafe(readSize);
|
|
161
|
+
const { bytesRead } = await fd.read(buf, 0, readSize, pos);
|
|
162
|
+
buffer = buf.toString("utf8", 0, bytesRead) + buffer;
|
|
163
|
+
if (pos === 0 && buffer.startsWith(delimiter)) startsWithDelimiter = true;
|
|
164
|
+
consumeBuffer();
|
|
165
|
+
}
|
|
166
|
+
if (pos === 0 && !flushed) {
|
|
167
|
+
flushTail();
|
|
171
168
|
if (fd) {
|
|
172
|
-
|
|
169
|
+
try {
|
|
170
|
+
await fd.close();
|
|
171
|
+
} catch {}
|
|
173
172
|
fd = null;
|
|
174
173
|
}
|
|
175
|
-
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
176
177
|
}
|
|
177
178
|
})();
|
|
178
179
|
function fillSync() {
|
|
179
|
-
if (done || closed) return;
|
|
180
|
-
if (fdSync === null) return;
|
|
180
|
+
if (done || closed || !fdSync) return;
|
|
181
181
|
while (pageQueue.count < prefetch && pos > 0 && !closed) {
|
|
182
182
|
const readSize = Math.min(chunkSize, pos);
|
|
183
183
|
pos -= readSize;
|
|
184
184
|
const buf = Buffer.allocUnsafe(readSize);
|
|
185
|
-
(0, node_fs.readSync)(fdSync, buf, 0, readSize, pos);
|
|
186
|
-
buffer = buf.toString("utf8") + buffer;
|
|
185
|
+
const bytesRead = (0, node_fs.readSync)(fdSync, buf, 0, readSize, pos);
|
|
186
|
+
buffer = buf.toString("utf8", 0, bytesRead) + buffer;
|
|
187
187
|
if (pos === 0 && buffer.startsWith(delimiter)) startsWithDelimiter = true;
|
|
188
|
-
|
|
189
|
-
while ((idx = buffer.lastIndexOf(delimiter)) !== -1) {
|
|
190
|
-
const line = buffer.slice(idx + delimiter.length);
|
|
191
|
-
buffer = buffer.slice(0, idx);
|
|
192
|
-
local.push(line);
|
|
193
|
-
while (local.length >= pageSize) {
|
|
194
|
-
const page = local.splice(0, pageSize);
|
|
195
|
-
pageQueue.push(page);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
188
|
+
consumeBuffer();
|
|
198
189
|
}
|
|
199
|
-
if (pos === 0 && !
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
local.length -= page.length;
|
|
206
|
-
pageQueue.push(page);
|
|
207
|
-
}
|
|
208
|
-
done = true;
|
|
209
|
-
if (fdSync !== null) {
|
|
210
|
-
(0, node_fs.closeSync)(fdSync);
|
|
190
|
+
if (pos === 0 && !flushed) {
|
|
191
|
+
flushTail();
|
|
192
|
+
if (fdSync) {
|
|
193
|
+
try {
|
|
194
|
+
(0, node_fs.closeSync)(fdSync);
|
|
195
|
+
} catch {}
|
|
211
196
|
fdSync = null;
|
|
212
197
|
}
|
|
213
|
-
pageQueue.wake();
|
|
214
198
|
}
|
|
215
199
|
}
|
|
216
200
|
async function next() {
|
|
@@ -223,20 +207,21 @@ function createBackwardReader(filepath, options) {
|
|
|
223
207
|
return pageQueue.shiftSync();
|
|
224
208
|
}
|
|
225
209
|
async function close() {
|
|
210
|
+
if (closed) return;
|
|
226
211
|
closed = true;
|
|
227
212
|
done = true;
|
|
228
213
|
pageQueue.clear();
|
|
229
|
-
if (
|
|
214
|
+
if (fdSync) {
|
|
230
215
|
try {
|
|
231
|
-
|
|
216
|
+
(0, node_fs.closeSync)(fdSync);
|
|
232
217
|
} catch {}
|
|
233
|
-
|
|
218
|
+
fdSync = null;
|
|
234
219
|
}
|
|
235
|
-
if (
|
|
220
|
+
if (fd) {
|
|
236
221
|
try {
|
|
237
|
-
|
|
222
|
+
await fd.close();
|
|
238
223
|
} catch {}
|
|
239
|
-
|
|
224
|
+
fd = null;
|
|
240
225
|
}
|
|
241
226
|
}
|
|
242
227
|
return {
|
|
@@ -265,14 +250,18 @@ function createBackwardReader(filepath, options) {
|
|
|
265
250
|
closed = true;
|
|
266
251
|
done = true;
|
|
267
252
|
pageQueue.clear();
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
253
|
+
if (fdSync) {
|
|
254
|
+
try {
|
|
255
|
+
(0, node_fs.closeSync)(fdSync);
|
|
256
|
+
} catch {}
|
|
257
|
+
fdSync = null;
|
|
258
|
+
}
|
|
259
|
+
if (fd?.fd) {
|
|
260
|
+
try {
|
|
261
|
+
(0, node_fs.closeSync)(fd.fd);
|
|
262
|
+
} catch {}
|
|
263
|
+
fd = null;
|
|
264
|
+
}
|
|
276
265
|
}
|
|
277
266
|
}
|
|
278
267
|
};
|
|
@@ -291,106 +280,90 @@ function createForwardReader(filepath, options) {
|
|
|
291
280
|
let done = false;
|
|
292
281
|
let closed = false;
|
|
293
282
|
let flushed = false;
|
|
283
|
+
function consumeBuffer() {
|
|
284
|
+
let idx;
|
|
285
|
+
while ((idx = buffer.indexOf(delimiter)) !== -1) {
|
|
286
|
+
const line = buffer.slice(0, idx);
|
|
287
|
+
buffer = buffer.slice(idx + delimiter.length);
|
|
288
|
+
local.push(line);
|
|
289
|
+
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function flushTail() {
|
|
293
|
+
if (flushed) return;
|
|
294
|
+
flushed = true;
|
|
295
|
+
local.push(buffer.length > 0 ? buffer : "");
|
|
296
|
+
buffer = "";
|
|
297
|
+
while (local.length > 0) pageQueue.push(local.splice(0, pageSize));
|
|
298
|
+
done = true;
|
|
299
|
+
pageQueue.wake();
|
|
300
|
+
}
|
|
294
301
|
fdSync = (0, node_fs.openSync)(filepath, "r");
|
|
295
302
|
size = (0, node_fs.statSync)(filepath).size;
|
|
296
303
|
if (size === 0) {
|
|
297
|
-
pageQueue.push([
|
|
304
|
+
pageQueue.push([""]);
|
|
298
305
|
done = true;
|
|
306
|
+
flushed = true;
|
|
299
307
|
pageQueue.wake();
|
|
300
308
|
}
|
|
301
309
|
(async () => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
if (fd) {
|
|
311
|
-
await fd.close();
|
|
312
|
-
fd = null;
|
|
313
|
-
}
|
|
314
|
-
pageQueue.wake();
|
|
315
|
-
return;
|
|
310
|
+
fd = await (0, node_fs_promises.open)(filepath, "r");
|
|
311
|
+
size = (await fd.stat()).size;
|
|
312
|
+
if (size === 0) {
|
|
313
|
+
if (!done) {
|
|
314
|
+
pageQueue.push([""]);
|
|
315
|
+
done = true;
|
|
316
|
+
flushed = true;
|
|
316
317
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
pos += bytesRead;
|
|
323
|
-
buffer = buffer + buf.toString("utf8", 0, bytesRead);
|
|
324
|
-
let idx;
|
|
325
|
-
while ((idx = buffer.indexOf(delimiter)) !== -1) {
|
|
326
|
-
const line = buffer.slice(0, idx);
|
|
327
|
-
buffer = buffer.slice(idx + delimiter.length);
|
|
328
|
-
local.push(line);
|
|
329
|
-
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
if (pos >= size && !flushed) {
|
|
333
|
-
flushed = true;
|
|
334
|
-
local.push(buffer.length > 0 ? buffer : "");
|
|
335
|
-
buffer = "";
|
|
336
|
-
while (local.length > 0 && !closed) {
|
|
337
|
-
const page = local.slice(0, pageSize);
|
|
338
|
-
local.length -= page.length;
|
|
339
|
-
pageQueue.push(page);
|
|
340
|
-
}
|
|
341
|
-
done = true;
|
|
342
|
-
if (fd) {
|
|
343
|
-
await fd.close();
|
|
344
|
-
fd = null;
|
|
345
|
-
}
|
|
346
|
-
pageQueue.wake();
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
318
|
+
if (fd) {
|
|
319
|
+
try {
|
|
320
|
+
await fd.close();
|
|
321
|
+
} catch {}
|
|
322
|
+
fd = null;
|
|
350
323
|
}
|
|
351
|
-
} catch {
|
|
352
|
-
done = true;
|
|
353
324
|
pageQueue.wake();
|
|
354
|
-
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
while (!done && !closed) {
|
|
328
|
+
while (pageQueue.count < prefetch && pos < size && !closed) {
|
|
329
|
+
const readSize = Math.min(chunkSize, size - pos);
|
|
330
|
+
const buf = Buffer.allocUnsafe(readSize);
|
|
331
|
+
const { bytesRead } = await fd.read(buf, 0, readSize, pos);
|
|
332
|
+
pos += bytesRead;
|
|
333
|
+
buffer = buffer + buf.toString("utf8", 0, bytesRead);
|
|
334
|
+
consumeBuffer();
|
|
335
|
+
}
|
|
336
|
+
if (pos >= size && !flushed) {
|
|
337
|
+
flushTail();
|
|
355
338
|
if (fd) {
|
|
356
|
-
|
|
339
|
+
try {
|
|
340
|
+
await fd.close();
|
|
341
|
+
} catch {}
|
|
357
342
|
fd = null;
|
|
358
343
|
}
|
|
359
|
-
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
360
347
|
}
|
|
361
348
|
})();
|
|
362
349
|
function fillSync() {
|
|
363
|
-
if (done || closed) return;
|
|
364
|
-
if (fdSync === null) return;
|
|
350
|
+
if (done || closed || !fdSync) return;
|
|
365
351
|
while (pageQueue.count < prefetch && pos < size && !closed) {
|
|
366
352
|
const readSize = Math.min(chunkSize, size - pos);
|
|
367
353
|
const buf = Buffer.allocUnsafe(readSize);
|
|
368
354
|
const bytesRead = (0, node_fs.readSync)(fdSync, buf, 0, readSize, pos);
|
|
369
355
|
pos += bytesRead;
|
|
370
356
|
buffer = buffer + buf.toString("utf8", 0, bytesRead);
|
|
371
|
-
|
|
372
|
-
while ((idx = buffer.indexOf(delimiter)) !== -1) {
|
|
373
|
-
const line = buffer.slice(0, idx);
|
|
374
|
-
buffer = buffer.slice(idx + delimiter.length);
|
|
375
|
-
local.push(line);
|
|
376
|
-
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
377
|
-
}
|
|
357
|
+
consumeBuffer();
|
|
378
358
|
}
|
|
379
359
|
if (pos >= size && !flushed) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
local.length -= page.length;
|
|
386
|
-
pageQueue.push(page);
|
|
387
|
-
}
|
|
388
|
-
done = true;
|
|
389
|
-
if (fdSync !== null) {
|
|
390
|
-
(0, node_fs.closeSync)(fdSync);
|
|
360
|
+
flushTail();
|
|
361
|
+
if (fdSync) {
|
|
362
|
+
try {
|
|
363
|
+
(0, node_fs.closeSync)(fdSync);
|
|
364
|
+
} catch {}
|
|
391
365
|
fdSync = null;
|
|
392
366
|
}
|
|
393
|
-
pageQueue.wake();
|
|
394
367
|
}
|
|
395
368
|
}
|
|
396
369
|
async function next() {
|
|
@@ -403,20 +376,21 @@ function createForwardReader(filepath, options) {
|
|
|
403
376
|
return pageQueue.shiftSync();
|
|
404
377
|
}
|
|
405
378
|
async function close() {
|
|
379
|
+
if (closed) return;
|
|
406
380
|
closed = true;
|
|
407
381
|
done = true;
|
|
408
382
|
pageQueue.clear();
|
|
409
|
-
if (
|
|
383
|
+
if (fdSync) {
|
|
410
384
|
try {
|
|
411
|
-
|
|
385
|
+
(0, node_fs.closeSync)(fdSync);
|
|
412
386
|
} catch {}
|
|
413
|
-
|
|
387
|
+
fdSync = null;
|
|
414
388
|
}
|
|
415
|
-
if (
|
|
389
|
+
if (fd) {
|
|
416
390
|
try {
|
|
417
|
-
|
|
391
|
+
await fd.close();
|
|
418
392
|
} catch {}
|
|
419
|
-
|
|
393
|
+
fd = null;
|
|
420
394
|
}
|
|
421
395
|
}
|
|
422
396
|
return {
|
|
@@ -445,14 +419,18 @@ function createForwardReader(filepath, options) {
|
|
|
445
419
|
closed = true;
|
|
446
420
|
done = true;
|
|
447
421
|
pageQueue.clear();
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
422
|
+
if (fdSync) {
|
|
423
|
+
try {
|
|
424
|
+
(0, node_fs.closeSync)(fdSync);
|
|
425
|
+
} catch {}
|
|
426
|
+
fdSync = null;
|
|
427
|
+
}
|
|
428
|
+
if (fd?.fd) {
|
|
429
|
+
try {
|
|
430
|
+
(0, node_fs.closeSync)(fd.fd);
|
|
431
|
+
} catch {}
|
|
432
|
+
fd = null;
|
|
433
|
+
}
|
|
456
434
|
}
|
|
457
435
|
}
|
|
458
436
|
};
|
|
@@ -462,18 +440,23 @@ function createForwardReader(filepath, options) {
|
|
|
462
440
|
const workerFile = new URL("./worker.mjs", require("url").pathToFileURL(__filename).href);
|
|
463
441
|
function createWorkerReader(filepath, options) {
|
|
464
442
|
const { prefetch } = options;
|
|
465
|
-
const pageQueue = createRingBuffer(Math.max(2, prefetch + 1));
|
|
466
443
|
let done = false;
|
|
467
444
|
let closed = false;
|
|
445
|
+
const pageQueue = createRingBuffer(Math.max(2, prefetch + 1));
|
|
468
446
|
const worker = new node_worker_threads.Worker(new URL(workerFile, require("url").pathToFileURL(__filename).href), { workerData: {
|
|
469
447
|
filepath,
|
|
470
448
|
options
|
|
471
449
|
} });
|
|
472
450
|
worker.on("message", (msg) => {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
451
|
+
switch (msg.type) {
|
|
452
|
+
case "page":
|
|
453
|
+
pageQueue.push(msg.data);
|
|
454
|
+
break;
|
|
455
|
+
case "done":
|
|
456
|
+
case "error":
|
|
457
|
+
done = true;
|
|
458
|
+
pageQueue.wake();
|
|
459
|
+
break;
|
|
477
460
|
}
|
|
478
461
|
});
|
|
479
462
|
worker.on("error", () => {
|
|
@@ -493,10 +476,13 @@ function createWorkerReader(filepath, options) {
|
|
|
493
476
|
return pageQueue.shiftSync();
|
|
494
477
|
}
|
|
495
478
|
async function close() {
|
|
479
|
+
if (closed) return;
|
|
496
480
|
closed = true;
|
|
497
481
|
done = true;
|
|
498
482
|
pageQueue.clear();
|
|
499
|
-
|
|
483
|
+
try {
|
|
484
|
+
await worker.terminate();
|
|
485
|
+
} catch {}
|
|
500
486
|
}
|
|
501
487
|
function tryClose() {
|
|
502
488
|
close().catch(() => {});
|
package/dist/main.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as PagerOptions, i as Pager, n as NativeAddon, o as ReaderOptions, r as NativeReaderOptions, s as WorkerMessage, t as createNativePager } from "./native-_NmVYcF6.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/main.d.ts
|
|
4
4
|
declare function createPager(filepath: string, options?: PagerOptions): Pager;
|
|
5
5
|
//#endregion
|
|
6
|
-
export {
|
|
6
|
+
export { NativeAddon, NativeReaderOptions, Pager, PagerOptions, ReaderOptions, WorkerMessage, createNativePager, createPager, createPager as default };
|
package/dist/main.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as PagerOptions, i as Pager, n as NativeAddon, o as ReaderOptions, r as NativeReaderOptions, s as WorkerMessage, t as createNativePager } from "./native-DGzYrMHK.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/main.d.ts
|
|
4
4
|
declare function createPager(filepath: string, options?: PagerOptions): Pager;
|
|
5
5
|
//#endregion
|
|
6
|
-
export {
|
|
6
|
+
export { NativeAddon, NativeReaderOptions, Pager, PagerOptions, ReaderOptions, WorkerMessage, createNativePager, createPager, createPager as default };
|