• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

albe / node-event-storage / 29698697950

19 Jul 2026 06:25PM UTC coverage: 98.229% (-0.07%) from 98.299%
29698697950

Pull #338

github

web-flow
Merge a386f8e55 into 0aeaf0185
Pull Request #338: Refactor storage handle management around a shared LRU FileHandlePool

1582 of 1645 branches covered (96.17%)

Branch coverage included in aggregate %.

244 of 249 new or added lines in 10 files covered. (97.99%)

1 existing line in 1 file now uncovered.

7346 of 7444 relevant lines covered (98.68%)

989.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.24
/src/FileHandlePool.js
1
import fs from 'fs';
4✔
2

4✔
3
/**
4✔
4
 * LRU pool for file descriptors shared across multiple file-backed objects.
4✔
5
 *
4✔
6
 * Targets are expected to expose `fileName` and `fileMode` and may implement
4✔
7
 * `onBeforeClose(fd, evicted)` to flush state before their descriptor closes.
4✔
8
 */
4✔
9
class FileHandlePool {
4✔
10

4✔
11
    /**
4✔
12
     * @param {number} [maxOpen=0] Maximum number of simultaneously open handles. 0 disables eviction.
4✔
13
     */
4✔
14
    constructor(maxOpen = 0) {
4✔
15
        this.maxOpen = maxOpen;
3,776✔
16
        this.handles = new Map();
3,776✔
17
    }
3,776✔
18

4✔
19
    /**
4✔
20
     * @param {object} target
4✔
21
     * @returns {number}
4✔
22
     */
4✔
23
    get(target) {
4✔
24
        const handle = this.handles.get(target);
59,036✔
25
        if (handle) {
59,036✔
26
            this.touch(target);
49,940✔
27
            return handle.fd;
49,940✔
28
        }
49,940✔
29

9,096✔
30
        this.evictLeastRecentlyUsedIfNeeded(target);
9,096✔
31
        const fd = fs.openSync(target.fileName, target.fileMode);
9,096✔
32
        this.handles.set(target, { fd });
9,096✔
33
        return fd;
9,096✔
34
    }
59,036✔
35

4✔
36
    /**
4✔
37
     * @param {object} target
4✔
38
     * @returns {boolean}
4✔
39
     */
4✔
40
    has(target) {
4✔
41
        return this.handles.has(target);
80✔
42
    }
80✔
43

4✔
44
    /**
4✔
45
     * @param {object} target
4✔
46
     * @param {boolean} [evicted=true]
4✔
47
     * @returns {boolean}
4✔
48
     */
4✔
49
    evict(target, evicted = true) {
4✔
50
        const handle = this.handles.get(target);
11,508✔
51
        if (!handle) {
11,508✔
52
            return false;
2,428✔
53
        }
2,428✔
54
        try {
9,080✔
55
            target.onBeforeClose?.(handle.fd, evicted);
11,508✔
56
        } finally {
11,508✔
57
            this.handles.delete(target);
9,080✔
58
            fs.closeSync(handle.fd);
9,080✔
59
        }
9,080✔
60
        return true;
9,080✔
61
    }
11,508✔
62

4✔
63
    /**
4✔
64
     * @param {object} target
4✔
65
     * @returns {void}
4✔
66
     */
4✔
67
    touch(target) {
4✔
68
        const handle = this.handles.get(target);
49,940✔
69
        if (!handle) {
49,940!
NEW
70
            return;
×
NEW
71
        }
×
72
        this.handles.delete(target);
49,940✔
73
        this.handles.set(target, handle);
49,940✔
74
    }
49,940✔
75

4✔
76
    /**
4✔
77
     * Evict the least-recently-used descriptor before opening another one.
4✔
78
     *
4✔
79
     * @param {object} target
4✔
80
     */
4✔
81
    evictLeastRecentlyUsedIfNeeded(target) {
4✔
82
        if (this.maxOpen <= 0) {
9,096✔
83
            return;
1,260✔
84
        }
1,260✔
85
        this.handles.delete(target);
7,836✔
86
        if (this.handles.size < this.maxOpen) {
9,096✔
87
            return;
7,784✔
88
        }
7,784✔
89
        const lruTarget = this.handles.keys().next().value;
52✔
90
        if (!lruTarget) {
9,096!
NEW
91
            return;
×
NEW
92
        }
×
93
        this.evict(lruTarget);
52✔
94
    }
9,096✔
95

4✔
96
    /**
4✔
97
     * @returns {number}
4✔
98
     */
4✔
99
    get openCount() {
4✔
100
        return this.handles.size;
20✔
101
    }
20✔
102

4✔
103
}
4✔
104

4✔
105
export default FileHandlePool;
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc