From 6663c9857d3144a08649e9b57da390df70a7cb29 Mon Sep 17 00:00:00 2001
From: Gregor MacLennan <gmaclennan@digital-democracy.org>
Date: Thu, 13 Jul 2023 12:32:42 +0100
Subject: [PATCH 1/2] breaking test for fd pool

---
 test/basic.js | 50 ++++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/test/basic.js b/test/basic.js
index 10b0263..790271e 100644
--- a/test/basic.js
+++ b/test/basic.js
@@ -454,34 +454,36 @@ test('unlink on uncreated file does not reject', async function (t) {
 })
 
 test('pool', function (t) {
-  t.plan(8)
+  const POOL_SIZE = 2
+  const RAF_COUNT = 10
+
+  t.plan((RAF_COUNT * 2) + 2)
 
-  const pool = RAF.createPool(2)
+  const pool = RAF.createPool(POOL_SIZE)
 
-  const a = new RAF(gen(), { pool })
-  const b = new RAF(gen(), { pool })
-  const c = new RAF(gen(), { pool })
+  const rafs = []
+  let pending = RAF_COUNT
+
+  for (let i = 0; i < RAF_COUNT; i++) {
+    const raf = new RAF(gen(), { pool })
+    rafs.push(raf)
+    raf.write(0, Buffer.from('hello'), done)
+  }
 
-  a.write(0, Buffer.from('hello'), function (err) {
+  function done (err) {
     t.absent(err, 'no error')
-    b.write(0, Buffer.from('hello'), function (err) {
-      t.absent(err, 'no error')
-      c.write(0, Buffer.from('hello'), function (err) {
-        t.absent(err, 'no error')
-        setTimeout(function () {
-          t.is(pool.active.length, 2)
-          const all = [a, b, c]
-          t.is(all.filter(f => f.suspended).length, 1)
-
-          for (const f of all) {
-            f.read(0, 5, function (_, buf) {
-              t.alike(buf, Buffer.from('hello'))
-            })
-          }
-        }, 100)
-      })
-    })
-  })
+    if (--pending !== 0) return
+    setTimeout(function () {
+      t.is(pool.active.length, POOL_SIZE)
+      t.is(rafs.filter(f => f.suspended).length, RAF_COUNT - POOL_SIZE)
+
+      for (const f of rafs) {
+        f.read(0, 5, function (_, buf) {
+          t.alike(buf, Buffer.from('hello'))
+        })
+      }
+    }, 100)
+  }
 })
 
 test('readonly mode', function (t) {

From 71c19fbec05513dd14022ad38df19af32101ed0b Mon Sep 17 00:00:00 2001
From: Gregor MacLennan <gmaclennan@digital-democracy.org>
Date: Thu, 13 Jul 2023 14:21:08 +0100
Subject: [PATCH 2/2] fix: alternative Pool implementation

---
 index.js      | 20 ++++++++------------
 test/basic.js |  2 +-
 2 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/index.js b/index.js
index 4824381..b75fd4c 100644
--- a/index.js
+++ b/index.js
@@ -23,25 +23,21 @@ const CREAT = constants.O_CREAT
 class Pool {
   constructor (maxSize) {
     this.maxSize = maxSize
-    this.active = []
+    this.active = new Set()
   }
 
   _onactive (file) {
-    // suspend a random one when the pool
-    if (this.active.length >= this.maxSize) {
-      const r = Math.floor(Math.random() * this.active.length)
-      this.active[r].suspend()
+    // suspend least recently inserted
+    if (this.active.size >= this.maxSize) {
+      const toSuspend = this.active[Symbol.iterator]().next().value
+      toSuspend.suspend()
+      this.active.delete(toSuspend)
     }
-
-    file._pi = this.active.push(file) - 1
+    this.active.add(file)
   }
 
   _oninactive (file) {
-    const head = this.active.pop()
-    if (head !== file) {
-      head._pi = file._pi
-      this.active[head._pi] = head
-    }
+    this.active.delete(file)
   }
 }
 
diff --git a/test/basic.js b/test/basic.js
index 790271e..00baa0a 100644
--- a/test/basic.js
+++ b/test/basic.js
@@ -474,7 +474,7 @@ test('pool', function (t) {
     t.absent(err, 'no error')
     if (--pending !== 0) return
     setTimeout(function () {
-      t.is(pool.active.length, POOL_SIZE)
+      t.is(pool.active.size, POOL_SIZE)
       t.is(rafs.filter(f => f.suspended).length, RAF_COUNT - POOL_SIZE)
 
       for (const f of rafs) {