Skip to content

Commit 3e498e2

Browse files
authored
support an fd pool to limit how many active fds are in use (#33)
* support an fd pool to limit how many active fds are in use * pool test * increase test timeout
1 parent 36ea56c commit 3e498e2

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

index.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ const RDONLY = constants.O_RDONLY
2020
const WRONLY = constants.O_WRONLY
2121
const CREAT = constants.O_CREAT
2222

23+
class Pool {
24+
constructor (maxSize) {
25+
this.maxSize = maxSize
26+
this.active = []
27+
}
28+
29+
_onactive (file) {
30+
// suspend a random one when the pool
31+
if (this.active.length >= this.maxSize) {
32+
const r = Math.floor(Math.random() * this.active.length)
33+
this.active[r].suspend()
34+
}
35+
36+
file._pi = this.active.push(file) - 1
37+
}
38+
39+
_oninactive (file) {
40+
const head = this.active.pop()
41+
if (head !== file) {
42+
head._pi = file._pi
43+
this.active[head._pi] = head
44+
}
45+
}
46+
}
47+
2348
module.exports = class RandomAccessFile extends RandomAccessStorage {
2449
constructor (filename, opts = {}) {
2550
const size = opts.size || (opts.truncate ? 0 : -1)
@@ -39,6 +64,8 @@ module.exports = class RandomAccessFile extends RandomAccessStorage {
3964

4065
this.mode = readable && writable ? RDWR : (readable ? RDONLY : WRONLY)
4166

67+
this._pi = 0 // pool index
68+
this._pool = opts.pool || null
4269
this._size = size
4370
this._rmdir = !!opts.rmdir
4471
this._lock = opts.lock === true
@@ -47,6 +74,10 @@ module.exports = class RandomAccessFile extends RandomAccessStorage {
4774
this._alwaysCreate = size >= 0
4875
}
4976

77+
static createPool (maxSize) {
78+
return new Pool(maxSize)
79+
}
80+
5081
_open (req) {
5182
const create = this._alwaysCreate || this.writing // .writing comes from RAS
5283
const self = this
@@ -92,7 +123,7 @@ module.exports = class RandomAccessFile extends RandomAccessStorage {
92123

93124
function ontruncate (err) {
94125
if (err) return onerrorafteropen(err)
95-
126+
if (self._pool !== null) self._pool._onactive(self)
96127
req.callback(null)
97128
}
98129

@@ -180,6 +211,7 @@ module.exports = class RandomAccessFile extends RandomAccessStorage {
180211

181212
function onclose (err) {
182213
if (err) return req.callback(err)
214+
if (self._pool !== null) self._pool._oninactive(self)
183215
self.fd = 0
184216
req.callback(null)
185217
}

test/basic.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ test('truncate', function (t) {
361361
})
362362

363363
test('open and close many times', function (t) {
364+
t.timeout(120000) // on ci sometimes this takes a while
364365
t.plan(3)
365366

366367
const name = gen()
@@ -438,6 +439,37 @@ test('unlink', async function (t) {
438439
}
439440
})
440441

442+
test('pool', function (t) {
443+
t.plan(8)
444+
445+
const pool = RAF.createPool(2)
446+
447+
const a = new RAF(gen(), { pool })
448+
const b = new RAF(gen(), { pool })
449+
const c = new RAF(gen(), { pool })
450+
451+
a.write(0, Buffer.from('hello'), function (err) {
452+
t.absent(err, 'no error')
453+
b.write(0, Buffer.from('hello'), function (err) {
454+
t.absent(err, 'no error')
455+
c.write(0, Buffer.from('hello'), function (err) {
456+
t.absent(err, 'no error')
457+
setTimeout(function () {
458+
t.is(pool.active.length, 2)
459+
const all = [a, b, c]
460+
t.is(all.filter(f => f.suspended).length, 1)
461+
462+
for (const f of all) {
463+
f.read(0, 5, function (_, buf) {
464+
t.alike(buf, Buffer.from('hello'))
465+
})
466+
}
467+
}, 100)
468+
})
469+
})
470+
})
471+
})
472+
441473
function gen () {
442474
return path.join(tmp, ++i + '.txt')
443475
}

0 commit comments

Comments
 (0)