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

NikolayMakhonin / time-limits / #16

14 Nov 2023 06:53AM UTC coverage: 80.664% (-1.4%) from 82.045%
#16

push

NikolayMakhonin
v1.0.0

218 of 303 branches covered (0.0%)

Branch coverage included in aggregate %.

10 of 10 new or added lines in 2 files covered. (100.0%)

9 existing lines in 3 files now uncovered.

487 of 571 relevant lines covered (85.29%)

107854.59 hits per line

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

84.3
/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, promiseAll} from '@flemist/async-utils'
1✔
5
import {Priority, AwaitPriority} from '@flemist/priority-queue'
2✔
6

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

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

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

3,430✔
15
  /** it returns false if the obj cannot be pushed into the object pool (if size >= maxSize) */
3,430✔
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,594✔
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,188✔
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,238✔
35
  ): Promise<TResult>
36

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

24,925✔
42
export type ObjectPoolArgs<TObject extends object> = {
12,475✔
43
  pool: IPool,
39,312✔
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,925✔
47
  holdObjects?: boolean | Set<TObject>
48
  create: () => Promise<TObject>|TObject
2✔
49
  destroy?: (obj: TObject) => Promise<void>|void
24,925✔
50
}
24,925✔
51

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

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

43,579!
77
  get pool() {
43,579!
78
    return this._pool
70,458✔
79
  }
80

81
  get availableObjects(): ReadonlyArray<TObject> {
82
    return this._availableObjects.objects
201,990✔
83
  }
31,245✔
84

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

×
90
  get(count: number): TObject[] {
91
    const objects = this._availableObjects.get(count)
25,440✔
92
    if (this._holdObjects && objects) {
75,605✔
93
      for (let i = 0, len = objects.length; i < len; i++) {
75,605✔
94
        this._holdObjects.add(objects[i])
151,210✔
95
      }
75,605✔
96
    }
97
    return objects
75,605✔
98
  }
24,925✔
99

100
  async release(objects: TObject[], start?: number, end?: number): Promise<number> {
101
    return this._release(objects, this._pool, start, end)
25,440✔
102
  }
103

2✔
104
  private async _release(objects: TObject[], pool: IPool, start?: number, end?: number): Promise<number> {
75,605✔
105
    if (start == null) {
31,822!
106
      start = 0
75,605✔
107
    }
280,245!
108
    if (end == null) {
75,605!
109
      end = objects.length
31,822✔
110
    }
75,605✔
111
    const tryReleaseCount = end - start
31,822!
112
    const releasedCount = await pool.release(tryReleaseCount, true)
31,822✔
113

114
    end = Math.min(objects.length, releasedCount)
31,822!
115
    this._availableObjects.release(objects, start, end)
31,822✔
UNCOV
116

×
117
    if (this._holdObjects) {
31,822✔
118
      for (let i = start; i < end; i++) {
15,912✔
119
        const obj = objects[i]
44,472✔
120
        if (obj != null) {
44,472!
121
          if (this._holdObjects) {
44,472!
122
            this._holdObjects.delete(obj)
44,472✔
123
          }
124
        }
27,130✔
125
      }
2,205✔
126
    }
127

2,205✔
128
    return releasedCount
31,822!
UNCOV
129
  }
×
130

131
  tick(abortSignal?: IAbortSignalFast): Promise<void> | void {
2,205✔
132
    return this._pool.tick(abortSignal)
1,103✔
133
  }
134

2,205✔
135
  async getWait(
2,205✔
136
    count: number,
137
    priority?: Priority,
2,205✔
138
    abortSignal?: IAbortSignalFast,
2,205✔
139
    awaitPriority?: AwaitPriority,
140
  ): Promise<TObject[]> {
24,925✔
141
    await this._pool.holdWait(count, priority, abortSignal, awaitPriority)
76,295✔
142
    return this.get(count)
25,440✔
143
  }
24,925✔
144

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

×
157
    let start
×
158
    if (!objects) {
25,440!
159
      objects = new Array<TObject>(count)
×
160
      start = 0
×
161
    }
24,925✔
UNCOV
162
    else {
×
163
      start = objects.length
25,440✔
164
    }
165

166
    for (let i = start; i < count; i++) {
25,440✔
167
      const obj = await this._create()
2,248✔
168
      if (obj == null) {
2,857!
UNCOV
169
        throw new Error('create function should return not null object')
×
170
      }
171
      if (this._holdObjects) {
2,857✔
172
        this._holdObjects.add(obj)
2,857✔
173
      }
2,857✔
174
      objects[i] = obj
2,248✔
175
    }
176
    try {
25,440!
177
      const result = await func(objects, abortSignal)
25,440✔
178
      return result
25,440✔
179
    }
2,857!
180
    finally {
2,857✔
181
      const releasedCount = await this.release(objects)
25,440✔
182
      if (this._destroy) {
25,440!
183
        for (let i = releasedCount, len = objects.length; i < len; i++) {
3,160✔
184
          const obj = objects[i]
×
185
          await this._destroy(obj)
3,160✔
186
        }
12,640!
187
      }
188
    }
3,160✔
189
  }
3,160✔
190

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

207
    let allocatedCount = 0
2,879✔
208
    const _this = this
2,879✔
209
    async function releasePromiseObject(objectPromise: Promise<TObject>) {
3,160✔
210
      let obj: TObject
211
      try {
3,192✔
212
        obj = await objectPromise
6,320✔
213
      }
3,160✔
214
      catch (err) {
215
        await _this._allocatePool.release(1)
3,160✔
216
        throw err
3,160✔
217
      }
3,160✔
218
      const count = await _this._release([obj], _this._allocatePool)
3,192✔
219
      allocatedCount += count
3,192✔
220
    }
221

222
    async function releasePromise(promise: Promise<number>) {
2,857✔
223
      const count = await promise
6,320✔
224
      allocatedCount += count
6,320✔
225
    }
3,160✔
226

227
    for (let i = 0; i < holdCount; i++) {
2,879✔
228
      const objectOrPromise = this._create()
6,382✔
229
      if (isPromiseLike(objectOrPromise)) {
6,382!
230
        promises.push(releasePromiseObject(objectOrPromise))
3,192✔
231
      }
232
      else {
233
        const promise = this._release([objectOrPromise], this._allocatePool)
3,190✔
234
        if (isPromiseLike(promise)) {
3,190!
235
          promises.push(releasePromise(promise))
3,190✔
236
        }
237
      }
572✔
238
    }
239
    if (promises.length) {
2,879✔
240
      return promiseAll(promises).then(o => allocatedCount)
2,303✔
241
    }
242

243
    return allocatedCount
576✔
244
  }
245
}
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

© 2026 Coveralls, Inc