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

NikolayMakhonin / time-limits / #7

pending completion
#7

push

NikolayMakhonin
v0.0.7

228 of 309 branches covered (73.79%)

Branch coverage included in aggregate %.

57 of 57 new or added lines in 5 files covered. (100.0%)

492 of 589 relevant lines covered (83.53%)

104193.86 hits per line

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

82.94
/src/object-pool/ObjectPool.ts
1
import {IAbortSignalFast} from '@flemist/abort-controller-fast'
2
import {IStackPool, StackPool} from 'src/object-pool/StackPool'
1✔
3
import {IPool, Pool, Pools} from 'src/pool'
1✔
4
import {isPromiseLike} from '@flemist/async-utils'
1✔
5
import {Priority, AwaitPriority} from '@flemist/priority-queue'
2✔
6

7
export interface IObjectPool<TObject extends object> {
3,421✔
8
  readonly pool: IPool
3,421✔
9

3,421✔
10
  readonly availableObjects: ReadonlyArray<TObject>
3,421✔
11
  readonly holdObjects?: ReadonlySet<TObject>
3,421✔
12

13
  get(count: number): TObject[]
3,424✔
14

3,421✔
15
  /** it returns false if the obj cannot be pushed into the object pool (if size >= maxSize) */
3,421✔
16
  release(objects: TObject[], start?: number, count?: number): Promise<number> | number
17

2✔
18
  /** it will resolve when size > 0 */
19
  tick(abortSignal?: IAbortSignalFast): Promise<void> | void
69,066✔
20

21
  /** wait available > 0 and get, use this for concurrency get */
22
  getWait(
23
    count: number,
24
    priority?: Priority,
2✔
25
    abortSignal?: IAbortSignalFast,
26
    awaitPriority?: AwaitPriority,
198,818✔
27
  ): Promise<TObject[]>
28

29
  use<TResult>(
30
    count: number,
31
    func: (objects: ReadonlyArray<TObject>, abortSignal?: IAbortSignalFast) => Promise<TResult> | TResult,
2✔
32
    priority?: Priority,
33
    abortSignal?: IAbortSignalFast,
34
    awaitPriority?: AwaitPriority,
126,183✔
35
  ): Promise<TResult>
36

37
  allocate(
38
    size?: number,
39
  ): Promise<number> | number
2✔
40
}
24,935✔
41

24,935✔
42
export type ObjectPoolArgs<TObject extends object> = {
12,480✔
43
  pool: IPool,
39,286✔
44
  /** custom availableObjects */
45
  availableObjects?: IStackPool<TObject>
46
  /** use holdObjects so that you can know which objects are taken and not released to the pool */
24,935✔
47
  holdObjects?: boolean | Set<TObject>
48
  create: () => Promise<TObject>|TObject
2✔
49
  destroy?: (obj: TObject) => Promise<void>|void
31,254✔
50
}
51

31,254✔
52
export class ObjectPool<TObject extends object> implements IObjectPool<TObject> {
62,508✔
53
  private readonly _pool: IPool
54
  private readonly _allocatePool: IPool
31,254!
55
  private readonly _availableObjects: IStackPool<TObject>
31,254✔
56
  private readonly _holdObjects: Set<TObject>
57
  private readonly _create?: () => Promise<TObject> | TObject
31,254!
58
  private readonly _destroy?: (obj: TObject) => Promise<void>|void
31,254✔
59

60
  constructor({
31,254✔
61
    pool,
31,254✔
62
    availableObjects,
63
    holdObjects,
31,254✔
64
    destroy,
31,254✔
65
    create,
31,254✔
66
  }: ObjectPoolArgs<TObject>) {
31,254✔
67
    this._allocatePool = new Pool(pool.maxSize)
15,646✔
68
    this._pool = new Pools(pool, this._allocatePool)
43,541✔
69
    this._availableObjects = availableObjects || new StackPool()
43,541!
70
    this._holdObjects = holdObjects === true
43,541!
71
      ? new Set<TObject>()
43,541✔
72
      : holdObjects || null
3,452✔
73
    this._create = create
3,453✔
74
    this._destroy = destroy
3,453✔
75
  }
76

31,254✔
77
  get pool() {
78
    return this._pool
70,326✔
79
  }
80

81
  get availableObjects(): ReadonlyArray<TObject> {
2✔
82
    return this._availableObjects.objects
202,994✔
83
  }
84

2✔
85
  /** which objects are taken and not released to the pool */
75,435✔
86
  get holdObjects(): ReadonlySet<TObject> {
75,435✔
87
    return this._holdObjects
150,870✔
88
  }
75,435✔
89

90
  get(count: number): TObject[] {
75,435✔
91
    const objects = this._availableObjects.get(count)
25,400✔
92
    if (this._holdObjects && objects) {
25,400✔
93
      for (let i = 0, len = objects.length; i < len; i++) {
12,710✔
94
        this._holdObjects.add(objects[i])
40,136✔
95
      }
96
    }
2✔
97
    return objects
75,435✔
98
  }
99

75,435✔
100
  async release(objects: TObject[], start?: number, end?: number): Promise<number> {
279,933!
101
    if (start == null) {
75,435!
102
      start = 0
31,778✔
103
    }
75,435✔
104
    if (end == null) {
31,778!
105
      end = objects.length
31,778✔
106
    }
107
    const tryReleaseCount = end - start
31,778!
108
    const releasedCount = await this._pool.release(tryReleaseCount)
31,778✔
109

×
110
    end = Math.min(objects.length, releasedCount)
31,778✔
111
    this._availableObjects.release(objects, start, end)
31,778✔
112

24,935✔
113
    if (this._holdObjects) {
31,778✔
114
      for (let i = start; i < end; i++) {
24,935✔
115
        const obj = objects[i]
44,450✔
116
        if (obj != null) {
44,450!
117
          if (this._holdObjects) {
44,450!
118
            this._holdObjects.delete(obj)
44,450✔
119
          }
120
        }
2,194✔
121
      }
2,194!
122
    }
×
123

124
    return releasedCount
31,778✔
125
  }
1,089✔
126

127
  tick(abortSignal?: IAbortSignalFast): Promise<void> | void {
2,194✔
128
    return this._pool.tick()
2,194✔
129
  }
130

2,194✔
131
  async getWait(
2,194✔
132
    count: number,
133
    priority?: Priority,
24,935✔
134
    abortSignal?: IAbortSignalFast,
24,935✔
135
    awaitPriority?: AwaitPriority,
136
  ): Promise<TObject[]> {
24,935✔
137
    await this._pool.holdWait(count, priority, abortSignal, awaitPriority)
76,265✔
138
    return this.get(count)
25,400✔
139
  }
140

24,935✔
141
  async use<TResult>(
24,935!
142
    count: number,
×
143
    func: (objects: ReadonlyArray<TObject>, abortSignal?: IAbortSignalFast) => Promise<TResult> | TResult,
×
144
    priority?: Priority,
145
    abortSignal?: IAbortSignalFast,
×
146
    awaitPriority?: AwaitPriority,
×
147
  ): Promise<TResult> {
×
148
    let objects = await this.getWait(count, priority, abortSignal, awaitPriority)
76,265✔
149
    if (!this._create) {
25,400!
150
      throw new Error('You should specify create function in the constructor')
×
151
    }
152

×
153
    let start
×
154
    if (!objects) {
25,400!
155
      objects = new Array<TObject>(count)
×
156
      start = 0
×
157
    }
158
    else {
159
      start = objects.length
25,400✔
160
    }
2✔
161

2,851!
162
    for (let i = start; i < count; i++) {
25,400✔
163
      const obj = await this._create()
2,245✔
164
      if (obj == null) {
2,851!
165
        throw new Error('create function should return not null object')
2,851✔
166
      }
2,851✔
167
      if (this._holdObjects) {
2,245✔
168
        this._holdObjects.add(obj)
1,124✔
169
      }
2,851!
170
      objects[i] = obj
2,245✔
171
    }
172
    try {
25,400!
173
      const result = await func(objects, abortSignal)
25,400✔
174
      return result
25,400✔
175
    }
176
    finally {
3,167✔
177
      const releasedCount = await this.release(objects)
25,400✔
178
      if (this._destroy) {
25,400!
179
        for (let i = releasedCount, len = objects.length; i < len; i++) {
12,668!
180
          const obj = objects[i]
×
181
          await this._destroy(obj)
3,167✔
182
        }
3,167✔
183
      }
184
    }
3,167✔
185
  }
3,167✔
186

187
  allocate(
×
188
    size?: number,
×
189
  ): Promise<number> | number {
190
    if (!this._create) {
2,877!
191
      throw new Error('You should specify create function in the constructor')
×
192
    }
3,167✔
193
    const promises: Promise<void>[] = []
2,877✔
194
    let tryHoldCount = this._allocatePool.size - this._availableObjects.size
3,167✔
195
    if (size != null && size < tryHoldCount) {
3,167✔
196
      tryHoldCount = size
3,167✔
197
    }
198
    if (tryHoldCount < 0) {
2,877!
199
      throw new Error('Unexpected behavior: tryHoldCount < 0')
×
200
    }
201
    const holdCount = this._allocatePool.hold(tryHoldCount) ? tryHoldCount : 0
2,877!
202

3,152✔
203
    let allocatedCount = 0
2,877✔
204
    const _this = this
3,152✔
205
    async function releasePromiseObject(objectPromise: Promise<TObject>) {
6,304✔
206
      let obj: TObject
3,152✔
207
      try {
3,188✔
208
        obj = await objectPromise
3,188✔
209
      }
3,152✔
210
      catch (err) {
3,152✔
211
        await _this._allocatePool.release(1)
×
212
        throw err
×
213
      }
214
      const count = await _this.release([obj])
3,188✔
215
      allocatedCount += count
3,188✔
216
    }
6,319✔
217

6,319✔
218
    async function releasePromise(promise: Promise<number>) {
3,167✔
219
      const count = await promise
3,190✔
220
      allocatedCount += count
3,190✔
221
    }
3,152✔
222

3,152!
223
    for (let i = 0; i < holdCount; i++) {
3,152✔
224
      const objectOrPromise = this._create()
6,378✔
225
      if (isPromiseLike(objectOrPromise)) {
6,378✔
226
        promises.push(releasePromiseObject(objectOrPromise))
3,188✔
227
      }
2,851✔
228
      else {
2,282✔
229
        const promise = this.release([objectOrPromise])
3,190✔
230
        if (isPromiseLike(promise)) {
3,190!
231
          promises.push(releasePromise(promise))
3,190✔
232
        }
2✔
233
      }
234
    }
235
    if (promises.length) {
2,877✔
236
      return Promise.all(promises).then(o => allocatedCount)
2,301✔
237
    }
238

239
    return allocatedCount
576✔
240
  }
241
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc