Skip to content

Commit 165a304

Browse files
fix: Allow to open database files >2GiB and optimize memory consumption for reading files (#878)
* Update index.ts * Update fs.ts * New contributor * Fix ts * allow to publish again while master branch is updated * Update package.json * Update index.ts * Update tests
1 parent 0e81d42 commit 165a304

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"Thomas Birke @quafzi <[email protected]>",
2424
"Afzaal Ameer @afzaalace",
2525
"Andrew N Golovkov @AndorCS",
26-
"Gregory Oschwald @oschwald"
26+
"Gregory Oschwald @oschwald",
27+
"Mariano Facundo Scigliano @MarianoFacundoArch"
2728
],
2829
"dependencies": {
2930
"mmdb-lib": "2.1.1",

Diff for: src/fs.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export default {
55
existsSync: fs.existsSync,
66
readFile: util.promisify(fs.readFile),
77
watchFile: fs.watchFile,
8+
createReadStream: fs.createReadStream,
89
};

Diff for: src/index.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('index', () => {
1818
sandbox.stub(fs, 'watchFile').callsFake((paramA, paramB, cb) => {
1919
watchHandler = cb;
2020
});
21-
sandbox.spy(fs, 'readFile');
21+
sandbox.spy(fs, 'createReadStream');
2222
});
2323
afterEach(() => {
2424
sandbox.restore();
@@ -51,17 +51,17 @@ describe('index', () => {
5151
const lookup = await maxmind.open(dbPath, options);
5252
assert(lookup.get('2001:230::'));
5353
assert((fs.watchFile as SinonSpy).calledOnce);
54-
assert((fs.readFile as SinonSpy).calledOnce);
54+
assert((fs.createReadStream as SinonSpy).calledOnce);
5555
});
5656

5757
it('should work with auto updates', async () => {
5858
const options = { watchForUpdates: true };
5959
const lookup = await maxmind.open(dbPath, options);
6060
assert(lookup.get('2001:230::'));
6161
assert((fs.watchFile as SinonSpy).calledOnce);
62-
assert((fs.readFile as SinonSpy).calledOnce);
62+
assert((fs.createReadStream as SinonSpy).calledOnce);
6363
await watchHandler();
64-
assert((fs.readFile as SinonSpy).calledTwice);
64+
assert((fs.createReadStream as SinonSpy).calledTwice);
6565
});
6666

6767
it('should work with auto updates and call specified hook', async () => {

Diff for: src/index.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,36 @@ export interface OpenOpts {
1717
watchForUpdatesHook?: Callback;
1818
}
1919

20+
const readFile = async (filepath: string): Promise<Buffer> => {
21+
return new Promise((resolve, reject) => {
22+
const chunks: Buffer[] = [];
23+
const stream = fs.createReadStream(filepath, {
24+
highWaterMark: 64 * 1024 * 1024, // 64 MB chunks
25+
});
26+
27+
stream.on('data', (chunk: Buffer) => {
28+
chunks.push(chunk);
29+
});
30+
31+
stream.on('end', () => {
32+
resolve(Buffer.concat(chunks));
33+
});
34+
35+
stream.on('error', (err) => {
36+
reject(err);
37+
});
38+
});
39+
};
40+
41+
2042
export const open = async <T extends Response>(
2143
filepath: string,
2244
opts?: OpenOpts,
2345
cb?: Callback
2446
): Promise<Reader<T>> => {
2547
assert(!cb, utils.legacyErrorMessage);
2648

27-
const database = await fs.readFile(filepath);
49+
const database = await readFile(filepath);
2850

2951
if (isGzip(database)) {
3052
throw new Error(
@@ -63,7 +85,7 @@ export const open = async <T extends Response>(
6385
if (!(await waitExists())) {
6486
return;
6587
}
66-
const updatedDatabase = await fs.readFile(filepath);
88+
const updatedDatabase = await readFile(filepath);
6789
cache.clear();
6890
reader.load(updatedDatabase);
6991
if (opts.watchForUpdatesHook) {

0 commit comments

Comments
 (0)