@amritk/nish-x86_64-linux 0.27.2 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/INSTALL.md +16 -8
  2. package/bin/nish +0 -0
  3. package/docs/AI.md +118 -26
  4. package/package.json +1 -1
  5. package/runtime/core/host.d.ts +2 -1
  6. package/runtime/core/host.mjs +4 -0
  7. package/runtime/core.d.ts +47 -0
  8. package/runtime/core.mjs +67 -0
  9. package/runtime/nish.d.ts +176 -0
  10. package/runtime/nish.h +120 -6
  11. package/runtime/nish.mjs +24 -4
  12. package/runtime/runtime-checksum.c +270 -0
  13. package/runtime/runtime-net.c +386 -5
  14. package/runtime/runtime-os.c +59 -8
  15. package/runtime/runtime-parallel.c +81 -5
  16. package/runtime/runtime-sandbox.c +479 -0
  17. package/runtime/runtime-sha256.c +239 -0
  18. package/runtime/runtime-shm.c +541 -0
  19. package/runtime/runtime.c +827 -791
  20. package/scripts/build.sh +79 -28
  21. package/std/README.md +25 -13
  22. package/std/collections.ts +5 -5
  23. package/std/compress/checksum.ts +88 -75
  24. package/std/compress/deflate.ts +224 -0
  25. package/std/compress/gzip.ts +52 -0
  26. package/std/crypto/bcrypt.ts +816 -280
  27. package/std/crypto/hmac.ts +305 -2
  28. package/std/crypto/jwt.ts +1661 -0
  29. package/std/json-equal.ts +335 -0
  30. package/std/json-format.ts +1070 -0
  31. package/std/json-number.ts +428 -0
  32. package/std/json-pointer.ts +245 -0
  33. package/std/json-typed.ts +34 -0
  34. package/std/json-value.ts +510 -17
  35. package/std/json.ts +35 -6
  36. package/std/net/handler.ts +1348 -0
  37. package/std/net/http-client.ts +97 -16
  38. package/std/net/http-compress.ts +301 -16
  39. package/std/net/http1-client.ts +104 -19
  40. package/std/net/http1-server.ts +127 -24
  41. package/std/net/http1.ts +24 -4
  42. package/std/net/outbound.ts +409 -0
  43. package/std/net/postgres.ts +405 -0
  44. package/std/net/prefork.ts +344 -20
  45. package/std/net/websocket.ts +295 -14
  46. package/std/regex.ts +613 -52
  47. package/std/secret.ts +1 -1
  48. package/std/sync/ring.ts +587 -0
  49. package/std/sync/shm.ts +284 -0
  50. package/std/term-io.ts +35 -8
  51. package/std/term-rate.ts +13 -1
  52. package/std/threads.ts +35 -3
  53. package/std/yaml-json.ts +841 -0
  54. /package/runtime/{LICENSE-ryu → LICENSE-zmij} +0 -0
@@ -142,6 +142,17 @@
142
142
  * take writes into may still grow, up to its `maxOutput`); when to take is
143
143
  * the program's.
144
144
  *
145
+ * **Batch timing.** `PgBatchClock` is one answer to when: given the time in
146
+ * microseconds, `check(now, inFlight)` says a batch is due once
147
+ * max(`minCount`, the moving average of recent batch sizes × `factor`) items
148
+ * wait, once the oldest has waited `maxWaitUs`, or, with the idle bypass on,
149
+ * at once when nothing is in flight and fewer than `lightCount` arrived in the
150
+ * last `lightWindowUs`; `average`, `lastSize`, `lastReason` and `startsFor`
151
+ * are its metrics. Its defaults are the fixed window. `PgBatcher.takeDue`
152
+ * takes only when its clock says so, and `PgBatchTurns` lets one free
153
+ * connection collect while the others execute, woken only when its batch is
154
+ * due. Neither reads a clock or allocates per item.
155
+ *
145
156
  * Written from PostgreSQL's "Frontend/Backend Protocol" chapter (version 18)
146
157
  * and RFC 5802 and RFC 7677; not ported from another implementation.
147
158
  */
@@ -2746,6 +2757,15 @@ export class PgPool {
2746
2757
  return this.queueCount
2747
2758
  }
2748
2759
 
2760
+ /** The number of groups in flight on every connection, sent and not yet done: the `inFlight` a `PgBatchClock` reads. */
2761
+ inFlight(): i32 {
2762
+ let n: i32 = 0
2763
+ for (const slot of this.slots) {
2764
+ n += slot.count
2765
+ }
2766
+ return n
2767
+ }
2768
+
2749
2769
  /**
2750
2770
  * Hands the oldest waiting request to a ready connection with room (the
2751
2771
  * one with the fewest in flight, or under `PgConfig.pack` the first), and
@@ -3299,6 +3319,29 @@ export class PgBatcher {
3299
3319
  return true
3300
3320
  }
3301
3321
 
3322
+ /**
3323
+ * `take(conn)` when `clock` says a batch is due at `nowUs`, with `inFlight`
3324
+ * of the program's executions or groups running (`PgPool.inFlight()`), and
3325
+ * the batch taken recorded in `clock`; -1 when it is not due or `take`
3326
+ * answers -1. The program calls `clock.arrived(now)` for each request it
3327
+ * adds. Panics when the clock's waiting count is not this batcher's, or its
3328
+ * `maxCount` is below `maxRequests`.
3329
+ */
3330
+ takeDue(conn: PgConnection, clock: PgBatchClock, nowUs: i64, inFlight: i32): i32 {
3331
+ if (clock.waiting() !== this.count || clock.maxCount < this.maxRequests) {
3332
+ panic("nish/net/postgres: PgBatcher.takeDue with a clock that does not mirror the batcher")
3333
+ }
3334
+ if (clock.check(nowUs, inFlight) === PG_CLOCK_WAIT) {
3335
+ return -1
3336
+ }
3337
+ const before: i32 = this.count
3338
+ const r: i32 = this.take(conn)
3339
+ if (r >= 0) {
3340
+ clock.started(before - this.count, nowUs)
3341
+ }
3342
+ return r
3343
+ }
3344
+
3302
3345
  /**
3303
3346
  * Binds the oldest waiting requests on `conn` as one execution of `sql`,
3304
3347
  * prepared there already, and answers its run's handle, which names this
@@ -3553,3 +3596,365 @@ export class PgBatcher {
3553
3596
  return PG_BATCH_NONE
3554
3597
  }
3555
3598
  }
3599
+
3600
+ // --- Batch timing --------------------------------------------------------------
3601
+
3602
+ /** `PgBatchClock.check`: not yet; wait for an item or for `deadline()`. */
3603
+ export const PG_CLOCK_WAIT: i32 = 0
3604
+ /** `PgBatchClock.check`: `minCount` items are waiting, and the average asks no more. */
3605
+ export const PG_CLOCK_COUNT: i32 = 1
3606
+ /** `PgBatchClock.check`: the moving average of recent batches, times `factor`, is waiting. */
3607
+ export const PG_CLOCK_AVERAGE: i32 = 2
3608
+ /** `PgBatchClock.check`: the oldest item has waited `maxWaitUs`. */
3609
+ export const PG_CLOCK_TIMER: i32 = 3
3610
+ /** `PgBatchClock.check`: nothing is in flight and little has arrived lately, so the item goes at once. */
3611
+ export const PG_CLOCK_IDLE: i32 = 4
3612
+
3613
+ const PG_CLOCK_MAX_COUNT: i32 = 1048576
3614
+ const PG_CLOCK_MAX_LIGHT: i32 = 1024
3615
+ // A minute: a longer wait is a stalled program, not a batching policy.
3616
+ const PG_CLOCK_MAX_WAIT: i64 = 60000000
3617
+ const PG_CLOCK_MAX_FACTOR: f64 = 64.0
3618
+
3619
+ /**
3620
+ * When a `PgBatchClock` starts a batch. The defaults are the fixed window:
3621
+ * a batch starts when `maxCount` items wait or the oldest has waited
3622
+ * `maxWaitUs`, whatever the load. To adapt, set `factor` (1.1 is a good
3623
+ * start), lower `minCount` (16), and turn on the idle bypass (`lightCount`
3624
+ * 8); `bench/pg-batch-clock.ts` measures each against the fixed windows.
3625
+ */
3626
+ export class PgBatchClockConfig {
3627
+ /** The share of the recent batch size that must wait before a batch starts, 0 to 64; 0 leaves the average out, the fixed window. Above 1 batches grow until the timer bounds them (fewer statements, more wait); below 1 they shrink toward `minCount`. */
3628
+ factor: f64 = 0.0
3629
+ /** How far each batch moves the average, over 0 up to 1. Higher follows a change of load sooner and jumps more on one odd batch. */
3630
+ weight: f64 = 0.25
3631
+ /** The longest the oldest item waits for others, in microseconds, 0 to a minute: the most latency batching adds when the load is light. */
3632
+ maxWaitUs: i64 = 10000
3633
+ /** The window `lightCount` counts arrivals over, in microseconds, 0 to a minute. */
3634
+ lightWindowUs: i64 = 10000
3635
+ /** The most items one batch takes, `PgBatchConfig.maxRequests` for a batcher's clock. The count to start never passes it, so a backlog always starts by count. */
3636
+ maxCount: i32 = 32
3637
+ /** The fewest items that start a batch by count. Lower answers sooner under light load and spends more statements per item; `maxCount` is the fixed window. */
3638
+ minCount: i32 = 32
3639
+ /** The idle bypass: with nothing in flight and fewer than `lightCount` items arrived in the last `lightWindowUs`, an item goes at once. 0, the default, turns it off; up to 1024. */
3640
+ lightCount: i32 = 0
3641
+ /** The most items waiting, 1 to 2^20: `PgBatchConfig.queueSize` for a batcher's clock. */
3642
+ queueSize: i32 = 1024
3643
+ }
3644
+
3645
+ /**
3646
+ * Says when to start a batch, sans-IO like `PgBatcher`: the program passes
3647
+ * the time, in microseconds from any fixed point, and the clock reads none.
3648
+ * It keeps the arrival time of each waiting item, oldest first, and the
3649
+ * moving average (EWMA) of the batches started. `check` answers the reason a
3650
+ * batch should start now, or `PG_CLOCK_WAIT`: the target count is waiting
3651
+ * (the larger of `minCount` and the average times `factor`, never more than
3652
+ * `maxCount`), the oldest has waited `maxWaitUs`, or, with the idle bypass on,
3653
+ * nothing is in flight and the load is light. `deadline()` is when the timer
3654
+ * fires, for a poll's timeout.
3655
+ *
3656
+ * Under a backlog the target is already waiting, so the batch starts by count
3657
+ * the moment a connection is free, and nothing waits on the timer; a batch
3658
+ * started by count is at least the target, so the average does not fall
3659
+ * while the backlog lasts. Only a batch the timer or the bypass starts can
3660
+ * be smaller than the average and pull it down, as the load falls.
3661
+ *
3662
+ * The program mirrors its queue: `arrived(now)` for each item queued,
3663
+ * `started(size, now)` for each batch taken, oldest items first. A
3664
+ * `PgBatcher` does both itself through `takeDue`; a program forming its own
3665
+ * batches calls them by hand. The fields after a start are for metrics.
3666
+ * Everything is allocated in the constructor; nothing per item.
3667
+ */
3668
+ export class PgBatchClock {
3669
+ /** The moving average of the batch sizes started, 0 before the first. */
3670
+ average: f64 = 0.0
3671
+ /** The size of the last batch started, 0 before the first. */
3672
+ lastSize: i32 = 0
3673
+ /** Why the last batch started: the reason `check` last answered, `PG_CLOCK_WAIT` when it started without one. */
3674
+ lastReason: i32 = 0
3675
+ /** How long the oldest item of the last batch waited, in microseconds. */
3676
+ lastWaitUs: i64 = 0
3677
+ readonly maxCount: i32
3678
+ private readonly minCount: i32
3679
+ private readonly factor: f64
3680
+ private readonly weight: f64
3681
+ private readonly maxWaitUs: i64
3682
+ private readonly lightWindowUs: i64
3683
+ // The waiting items' arrival times, a ring from `head`; and the last
3684
+ // `lightCount` arrivals', a ring of their own, `lightAt` the next to write.
3685
+ private readonly times: i64[]
3686
+ private readonly light: i64[]
3687
+ private readonly starts: i64[]
3688
+ private head: i32 = 0
3689
+ private count: i32 = 0
3690
+ private lightAt: i32 = 0
3691
+ private lightSeen: i32 = 0
3692
+ private last: i64 = 0
3693
+ private due: i32 = 0
3694
+
3695
+ /** A clock for `config`; panics when a setting is out of the range its field names. */
3696
+ constructor(config: PgBatchClockConfig) {
3697
+ const factor: f64 = config.factor
3698
+ const weight: f64 = config.weight
3699
+ if (
3700
+ config.maxCount < 1 ||
3701
+ config.maxCount > PG_CLOCK_MAX_COUNT ||
3702
+ config.minCount < 1 ||
3703
+ config.minCount > config.maxCount ||
3704
+ !(factor >= 0.0 && factor <= PG_CLOCK_MAX_FACTOR) ||
3705
+ !(weight > 0.0 && weight <= 1.0) ||
3706
+ config.maxWaitUs < 0 ||
3707
+ config.maxWaitUs > PG_CLOCK_MAX_WAIT ||
3708
+ config.lightCount < 0 ||
3709
+ config.lightCount > PG_CLOCK_MAX_LIGHT ||
3710
+ config.lightWindowUs < 0 ||
3711
+ config.lightWindowUs > PG_CLOCK_MAX_WAIT ||
3712
+ config.queueSize < 1 ||
3713
+ config.queueSize > PG_BATCH_MAX_QUEUE
3714
+ ) {
3715
+ panic("nish/net/postgres: a PgBatchClockConfig setting out of range")
3716
+ }
3717
+ this.maxCount = config.maxCount
3718
+ this.minCount = config.minCount
3719
+ this.factor = factor
3720
+ this.weight = weight
3721
+ this.maxWaitUs = config.maxWaitUs
3722
+ this.lightWindowUs = config.lightWindowUs
3723
+ this.times = new Array<i64>(config.queueSize)
3724
+ this.light = new Array<i64>(config.lightCount)
3725
+ this.starts = new Array<i64>(5)
3726
+ }
3727
+
3728
+ /** The number of items waiting. */
3729
+ waiting(): i32 {
3730
+ return this.count
3731
+ }
3732
+
3733
+ /**
3734
+ * Records an item queued at `nowUs`; false when `queueSize` are waiting. A
3735
+ * time before the last one given counts as the last one, so a clock that
3736
+ * steps back cannot make an item older than its neighbours.
3737
+ */
3738
+ arrived(nowUs: i64): boolean {
3739
+ const ring: i32 = toI32(this.times.length)
3740
+ if (this.count === ring) {
3741
+ return false
3742
+ }
3743
+ const now: i64 = nowUs < this.last ? this.last : nowUs
3744
+ this.last = now
3745
+ this.times[(this.head + this.count) % ring] = now
3746
+ this.count += 1
3747
+ const lights: i32 = toI32(this.light.length)
3748
+ if (lights > 0) {
3749
+ this.light[this.lightAt] = now
3750
+ this.lightAt = (this.lightAt + 1) % lights
3751
+ if (this.lightSeen < lights) {
3752
+ this.lightSeen += 1
3753
+ }
3754
+ }
3755
+ return true
3756
+ }
3757
+
3758
+ /** The count that starts a batch now: the larger of `minCount` and the average times `factor`, at most `maxCount`. */
3759
+ target(): i32 {
3760
+ const scaled: f64 = Math.ceil(this.average * this.factor)
3761
+ let target: i32 = this.minCount
3762
+ if (scaled > toF64(target)) {
3763
+ target = toI32(scaled)
3764
+ }
3765
+ return target < this.maxCount ? target : this.maxCount
3766
+ }
3767
+
3768
+ /**
3769
+ * The reason a batch should start at `nowUs`, with `inFlight` batches (or
3770
+ * groups) still running, or `PG_CLOCK_WAIT`. It only says; the program
3771
+ * starts the batch when a connection is free, then calls `started`.
3772
+ */
3773
+ check(nowUs: i64, inFlight: i32): i32 {
3774
+ let reason: i32 = PG_CLOCK_WAIT
3775
+ if (this.count > 0) {
3776
+ const target: i32 = this.target()
3777
+ if (this.count >= target) {
3778
+ reason = target > this.minCount ? PG_CLOCK_AVERAGE : PG_CLOCK_COUNT
3779
+ } else if (nowUs - this.times[this.head] >= this.maxWaitUs) {
3780
+ reason = PG_CLOCK_TIMER
3781
+ } else if (inFlight <= 0 && this.quiet(nowUs)) {
3782
+ reason = PG_CLOCK_IDLE
3783
+ }
3784
+ }
3785
+ this.due = reason
3786
+ return reason
3787
+ }
3788
+
3789
+ /** When the oldest waiting item has waited `maxWaitUs`, in the caller's microseconds; -1 when none waits. */
3790
+ deadline(): i64 {
3791
+ if (this.count === 0) {
3792
+ return -1
3793
+ }
3794
+ return this.times[this.head] + this.maxWaitUs
3795
+ }
3796
+
3797
+ /**
3798
+ * Records a batch of the `size` oldest items started at `nowUs`, and moves
3799
+ * the average toward it; the first batch sets it. Panics when `size` is
3800
+ * below 1 or more than are waiting or than `maxCount`.
3801
+ */
3802
+ started(size: i32, nowUs: i64): void {
3803
+ if (size < 1 || size > this.count || size > this.maxCount) {
3804
+ panic("nish/net/postgres: PgBatchClock.started with a size out of range")
3805
+ }
3806
+ this.lastWaitUs = nowUs - this.times[this.head]
3807
+ if (this.lastWaitUs < 0) {
3808
+ this.lastWaitUs = 0
3809
+ }
3810
+ this.head = (this.head + size) % toI32(this.times.length)
3811
+ this.count -= size
3812
+ const n: f64 = toF64(size)
3813
+ this.average = this.lastSize === 0 ? n : this.average + this.weight * (n - this.average)
3814
+ this.lastSize = size
3815
+ this.lastReason = this.due
3816
+ this.starts[this.due] += 1
3817
+ this.due = PG_CLOCK_WAIT
3818
+ }
3819
+
3820
+ /** How many batches have started for `reason`, one of the `PG_CLOCK_*` (`PG_CLOCK_WAIT` counts those started without a due `check`). */
3821
+ startsFor(reason: i32): i64 {
3822
+ if (reason < 0 || reason > PG_CLOCK_IDLE) {
3823
+ panic("nish/net/postgres: PgBatchClock.startsFor with a reason out of range")
3824
+ }
3825
+ return this.starts[reason]
3826
+ }
3827
+
3828
+ /** Whether fewer than `lightCount` items arrived in the `lightWindowUs` before `nowUs`. */
3829
+ private quiet(nowUs: i64): boolean {
3830
+ const lights: i32 = toI32(this.light.length)
3831
+ if (lights === 0) {
3832
+ return false
3833
+ }
3834
+ if (this.lightSeen < lights) {
3835
+ return true
3836
+ }
3837
+ // `lightAt` is the next to write, so it holds the oldest of the last `lightCount`.
3838
+ return nowUs - this.light[this.lightAt] >= this.lightWindowUs
3839
+ }
3840
+ }
3841
+
3842
+ /** `PgBatchTurns`: no slot to wake. */
3843
+ export const PG_TURNS_NONE: i32 = -1
3844
+ /** `PgBatchTurns.push`: the item was not recorded, `queueSize` are waiting. */
3845
+ export const PG_TURNS_FULL: i32 = -2
3846
+
3847
+ /**
3848
+ * Turn-taking for a program with several connections that forms batches
3849
+ * with one `PgBatchClock`: one free connection, the collector, gathers while
3850
+ * the others execute, and a push wakes it only when its batch is due, not on
3851
+ * every item. Sans-IO like the clock: a slot is the program's own number for
3852
+ * a connection, 0 to `size - 1`, and the answer to each call is the slot to
3853
+ * wake, or `PG_TURNS_NONE`.
3854
+ *
3855
+ * The collector is the lowest-numbered free slot. `push(now)` records an item
3856
+ * and answers the collector when this item makes the batch due; `poll(now)`
3857
+ * answers it when the timer has made it due, at `deadline()`. Once a slot is
3858
+ * named, no other is until it calls `started(slot, size, now)` with the batch
3859
+ * it took, or `release(slot)` when it took none. `finished(slot, now)` frees
3860
+ * a slot after its batch. Both `started` and `finished` answer the next slot
3861
+ * to wake when a batch is already due, as under a backlog: nothing waits on
3862
+ * the timer then. The in-flight count the idle bypass reads is the slots
3863
+ * holding a batch.
3864
+ */
3865
+ export class PgBatchTurns {
3866
+ /** The clock the turns read and record into. */
3867
+ readonly clock: PgBatchClock
3868
+ /** The number of slots. */
3869
+ readonly size: i32
3870
+ private readonly busy: boolean[]
3871
+ private running: i32 = 0
3872
+ private woken: i32 = -1
3873
+
3874
+ /** Turns over `size` slots (1 to 1024), all free; panics on a size out of range. */
3875
+ constructor(clock: PgBatchClock, size: i32) {
3876
+ if (size < 1 || size > PG_POOL_MAX_SLOTS) {
3877
+ panic("nish/net/postgres: a PgBatchTurns size out of range")
3878
+ }
3879
+ this.clock = clock
3880
+ this.size = size
3881
+ this.busy = new Array<boolean>(size)
3882
+ }
3883
+
3884
+ /** The slot that collects: the lowest-numbered free one, or `PG_TURNS_NONE` when every slot holds a batch. */
3885
+ collector(): i32 {
3886
+ for (let i: i32 = 0; i < this.size; i++) {
3887
+ if (!this.busy[i]) {
3888
+ return i
3889
+ }
3890
+ }
3891
+ return PG_TURNS_NONE
3892
+ }
3893
+
3894
+ /** The number of slots holding a batch. */
3895
+ inFlight(): i32 {
3896
+ return this.running
3897
+ }
3898
+
3899
+ /** When the collector's timer fires, `PgBatchClock.deadline()`; -1 when nothing waits. */
3900
+ deadline(): i64 {
3901
+ return this.clock.deadline()
3902
+ }
3903
+
3904
+ /** Records an item queued at `nowUs` and answers the slot to wake, or `PG_TURNS_FULL` when the clock is full. */
3905
+ push(nowUs: i64): i32 {
3906
+ if (!this.clock.arrived(nowUs)) {
3907
+ return PG_TURNS_FULL
3908
+ }
3909
+ return this.poll(nowUs)
3910
+ }
3911
+
3912
+ /** The slot to wake at `nowUs`, when a batch is due and no slot is named already. */
3913
+ poll(nowUs: i64): i32 {
3914
+ if (this.woken >= 0) {
3915
+ return PG_TURNS_NONE
3916
+ }
3917
+ const slot: i32 = this.collector()
3918
+ if (slot < 0 || this.clock.check(nowUs, this.running) === PG_CLOCK_WAIT) {
3919
+ return PG_TURNS_NONE
3920
+ }
3921
+ this.woken = slot
3922
+ return slot
3923
+ }
3924
+
3925
+ /** Records `slot` starting a batch of `size` items at `nowUs`, and answers the next slot to wake. Panics on a slot out of range or holding a batch already, or as `PgBatchClock.started`. */
3926
+ started(slot: i32, size: i32, nowUs: i64): i32 {
3927
+ this.free(slot)
3928
+ this.clock.started(size, nowUs)
3929
+ this.busy[slot] = true
3930
+ this.running += 1
3931
+ if (this.woken === slot) {
3932
+ this.woken = -1
3933
+ }
3934
+ return this.poll(nowUs)
3935
+ }
3936
+
3937
+ /** Records `slot`'s batch done at `nowUs`, and answers the slot to wake. Panics on a slot out of range or holding no batch. */
3938
+ finished(slot: i32, nowUs: i64): i32 {
3939
+ if (slot < 0 || slot >= this.size || !this.busy[slot]) {
3940
+ panic("nish/net/postgres: PgBatchTurns.finished on a slot holding no batch")
3941
+ }
3942
+ this.busy[slot] = false
3943
+ this.running -= 1
3944
+ return this.poll(nowUs)
3945
+ }
3946
+
3947
+ /** Gives back a wake that started nothing, so the next push or poll can wake a slot again. */
3948
+ release(slot: i32): void {
3949
+ this.free(slot)
3950
+ if (this.woken === slot) {
3951
+ this.woken = -1
3952
+ }
3953
+ }
3954
+
3955
+ private free(slot: i32): void {
3956
+ if (slot < 0 || slot >= this.size || this.busy[slot]) {
3957
+ panic("nish/net/postgres: PgBatchTurns slot out of range or holding a batch")
3958
+ }
3959
+ }
3960
+ }