@@ -332,163 +332,168 @@ class QuicSessionStats { |
332 | 332 | * @param {symbol} privateSymbol |
333 | 333 | * @param {ArrayBuffer} buffer |
334 | 334 | */ |
335 | | - constructor(privateSymbol, buffer) { |
| 335 | + /** @type {number} */ |
| 336 | + #offset = 0; |
| 337 | + |
| 338 | + constructor(privateSymbol, view, byteOffset = 0) { |
336 | 339 | // We use the kPrivateConstructor symbol to restrict the ability to |
337 | 340 | // create new instances of QuicSessionStats to internal code. |
338 | 341 | if (privateSymbol !== kPrivateConstructor) { |
339 | 342 | throw new ERR_ILLEGAL_CONSTRUCTOR(); |
340 | 343 | } |
341 | | - if (!isArrayBuffer(buffer)) { |
342 | | - throw new ERR_INVALID_ARG_TYPE('buffer', ['ArrayBuffer'], buffer); |
| 344 | + if (isArrayBuffer(view)) { |
| 345 | + this.#handle = new BigUint64Array(view); |
| 346 | + } else { |
| 347 | + this.#handle = view; |
343 | 348 | } |
344 | | - this.#handle = new BigUint64Array(buffer); |
| 349 | + this.#offset = byteOffset / 8; |
345 | 350 | } |
346 | 351 |
|
347 | 352 | /** @type {bigint} */ |
348 | 353 | get createdAt() { |
349 | | - return this.#handle[IDX_STATS_SESSION_CREATED_AT]; |
| 354 | + return this.#handle[this.#offset + IDX_STATS_SESSION_CREATED_AT]; |
350 | 355 | } |
351 | 356 |
|
352 | 357 | /** @type {bigint} */ |
353 | 358 | get destroyedAt() { |
354 | | - return this.#handle[IDX_STATS_SESSION_DESTROYED_AT]; |
| 359 | + return this.#handle[this.#offset + IDX_STATS_SESSION_DESTROYED_AT]; |
355 | 360 | } |
356 | 361 |
|
357 | 362 | /** @type {bigint} */ |
358 | 363 | get closingAt() { |
359 | | - return this.#handle[IDX_STATS_SESSION_CLOSING_AT]; |
| 364 | + return this.#handle[this.#offset + IDX_STATS_SESSION_CLOSING_AT]; |
360 | 365 | } |
361 | 366 |
|
362 | 367 | /** @type {bigint} */ |
363 | 368 | get handshakeCompletedAt() { |
364 | | - return this.#handle[IDX_STATS_SESSION_HANDSHAKE_COMPLETED_AT]; |
| 369 | + return this.#handle[this.#offset + IDX_STATS_SESSION_HANDSHAKE_COMPLETED_AT]; |
365 | 370 | } |
366 | 371 |
|
367 | 372 | /** @type {bigint} */ |
368 | 373 | get handshakeConfirmedAt() { |
369 | | - return this.#handle[IDX_STATS_SESSION_HANDSHAKE_CONFIRMED_AT]; |
| 374 | + return this.#handle[this.#offset + IDX_STATS_SESSION_HANDSHAKE_CONFIRMED_AT]; |
370 | 375 | } |
371 | 376 |
|
372 | 377 | /** @type {bigint} */ |
373 | 378 | get bytesReceived() { |
374 | | - return this.#handle[IDX_STATS_SESSION_BYTES_RECEIVED]; |
| 379 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_RECEIVED]; |
375 | 380 | } |
376 | 381 |
|
377 | 382 | /** @type {bigint} */ |
378 | 383 | get bidiInStreamCount() { |
379 | | - return this.#handle[IDX_STATS_SESSION_BIDI_IN_STREAM_COUNT]; |
| 384 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BIDI_IN_STREAM_COUNT]; |
380 | 385 | } |
381 | 386 |
|
382 | 387 | /** @type {bigint} */ |
383 | 388 | get bidiOutStreamCount() { |
384 | | - return this.#handle[IDX_STATS_SESSION_BIDI_OUT_STREAM_COUNT]; |
| 389 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BIDI_OUT_STREAM_COUNT]; |
385 | 390 | } |
386 | 391 |
|
387 | 392 | /** @type {bigint} */ |
388 | 393 | get uniInStreamCount() { |
389 | | - return this.#handle[IDX_STATS_SESSION_UNI_IN_STREAM_COUNT]; |
| 394 | + return this.#handle[this.#offset + IDX_STATS_SESSION_UNI_IN_STREAM_COUNT]; |
390 | 395 | } |
391 | 396 |
|
392 | 397 | /** @type {bigint} */ |
393 | 398 | get uniOutStreamCount() { |
394 | | - return this.#handle[IDX_STATS_SESSION_UNI_OUT_STREAM_COUNT]; |
| 399 | + return this.#handle[this.#offset + IDX_STATS_SESSION_UNI_OUT_STREAM_COUNT]; |
395 | 400 | } |
396 | 401 |
|
397 | 402 | /** @type {bigint} */ |
398 | 403 | get maxBytesInFlight() { |
399 | | - return this.#handle[IDX_STATS_SESSION_MAX_BYTES_IN_FLIGHT]; |
| 404 | + return this.#handle[this.#offset + IDX_STATS_SESSION_MAX_BYTES_IN_FLIGHT]; |
400 | 405 | } |
401 | 406 |
|
402 | 407 | /** @type {bigint} */ |
403 | 408 | get bytesInFlight() { |
404 | | - return this.#handle[IDX_STATS_SESSION_BYTES_IN_FLIGHT]; |
| 409 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_IN_FLIGHT]; |
405 | 410 | } |
406 | 411 |
|
407 | 412 | /** @type {bigint} */ |
408 | 413 | get blockCount() { |
409 | | - return this.#handle[IDX_STATS_SESSION_BLOCK_COUNT]; |
| 414 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BLOCK_COUNT]; |
410 | 415 | } |
411 | 416 |
|
412 | 417 | /** @type {bigint} */ |
413 | 418 | get cwnd() { |
414 | | - return this.#handle[IDX_STATS_SESSION_CWND]; |
| 419 | + return this.#handle[this.#offset + IDX_STATS_SESSION_CWND]; |
415 | 420 | } |
416 | 421 |
|
417 | 422 | /** @type {bigint} */ |
418 | 423 | get latestRtt() { |
419 | | - return this.#handle[IDX_STATS_SESSION_LATEST_RTT]; |
| 424 | + return this.#handle[this.#offset + IDX_STATS_SESSION_LATEST_RTT]; |
420 | 425 | } |
421 | 426 |
|
422 | 427 | /** @type {bigint} */ |
423 | 428 | get minRtt() { |
424 | | - return this.#handle[IDX_STATS_SESSION_MIN_RTT]; |
| 429 | + return this.#handle[this.#offset + IDX_STATS_SESSION_MIN_RTT]; |
425 | 430 | } |
426 | 431 |
|
427 | 432 | /** @type {bigint} */ |
428 | 433 | get rttVar() { |
429 | | - return this.#handle[IDX_STATS_SESSION_RTTVAR]; |
| 434 | + return this.#handle[this.#offset + IDX_STATS_SESSION_RTTVAR]; |
430 | 435 | } |
431 | 436 |
|
432 | 437 | /** @type {bigint} */ |
433 | 438 | get smoothedRtt() { |
434 | | - return this.#handle[IDX_STATS_SESSION_SMOOTHED_RTT]; |
| 439 | + return this.#handle[this.#offset + IDX_STATS_SESSION_SMOOTHED_RTT]; |
435 | 440 | } |
436 | 441 |
|
437 | 442 | /** @type {bigint} */ |
438 | 443 | get ssthresh() { |
439 | | - return this.#handle[IDX_STATS_SESSION_SSTHRESH]; |
| 444 | + return this.#handle[this.#offset + IDX_STATS_SESSION_SSTHRESH]; |
440 | 445 | } |
441 | 446 |
|
442 | 447 | get pktSent() { |
443 | | - return this.#handle[IDX_STATS_SESSION_PKT_SENT]; |
| 448 | + return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_SENT]; |
444 | 449 | } |
445 | 450 |
|
446 | 451 | get bytesSent() { |
447 | | - return this.#handle[IDX_STATS_SESSION_BYTES_SENT]; |
| 452 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_SENT]; |
448 | 453 | } |
449 | 454 |
|
450 | 455 | get pktRecv() { |
451 | | - return this.#handle[IDX_STATS_SESSION_PKT_RECV]; |
| 456 | + return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_RECV]; |
452 | 457 | } |
453 | 458 |
|
454 | 459 | get bytesRecv() { |
455 | | - return this.#handle[IDX_STATS_SESSION_BYTES_RECV]; |
| 460 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_RECV]; |
456 | 461 | } |
457 | 462 |
|
458 | 463 | get pktLost() { |
459 | | - return this.#handle[IDX_STATS_SESSION_PKT_LOST]; |
| 464 | + return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_LOST]; |
460 | 465 | } |
461 | 466 |
|
462 | 467 | get bytesLost() { |
463 | | - return this.#handle[IDX_STATS_SESSION_BYTES_LOST]; |
| 468 | + return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_LOST]; |
464 | 469 | } |
465 | 470 |
|
466 | 471 | get pingRecv() { |
467 | | - return this.#handle[IDX_STATS_SESSION_PING_RECV]; |
| 472 | + return this.#handle[this.#offset + IDX_STATS_SESSION_PING_RECV]; |
468 | 473 | } |
469 | 474 |
|
470 | 475 | get pktDiscarded() { |
471 | | - return this.#handle[IDX_STATS_SESSION_PKT_DISCARDED]; |
| 476 | + return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_DISCARDED]; |
472 | 477 | } |
473 | 478 |
|
474 | 479 | /** @type {bigint} */ |
475 | 480 | get datagramsReceived() { |
476 | | - return this.#handle[IDX_STATS_SESSION_DATAGRAMS_RECEIVED]; |
| 481 | + return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_RECEIVED]; |
477 | 482 | } |
478 | 483 |
|
479 | 484 | /** @type {bigint} */ |
480 | 485 | get datagramsSent() { |
481 | | - return this.#handle[IDX_STATS_SESSION_DATAGRAMS_SENT]; |
| 486 | + return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_SENT]; |
482 | 487 | } |
483 | 488 |
|
484 | 489 | /** @type {bigint} */ |
485 | 490 | get datagramsAcknowledged() { |
486 | | - return this.#handle[IDX_STATS_SESSION_DATAGRAMS_ACKNOWLEDGED]; |
| 491 | + return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_ACKNOWLEDGED]; |
487 | 492 | } |
488 | 493 |
|
489 | 494 | /** @type {bigint} */ |
490 | 495 | get datagramsLost() { |
491 | | - return this.#handle[IDX_STATS_SESSION_DATAGRAMS_LOST]; |
| 496 | + return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_LOST]; |
492 | 497 | } |
493 | 498 |
|
494 | 499 | toString() { |
@@ -590,88 +595,99 @@ class QuicSessionStats { |
590 | 595 | } |
591 | 596 |
|
592 | 597 | [kFinishClose]() { |
593 | | - // Snapshot the stats into a new BigUint64Array since the underlying |
594 | | - // buffer will be destroyed. |
595 | | - this.#handle = new BigUint64Array(this.#handle); |
| 598 | + // Snapshot this session's stats slice into a standalone BigUint64Array. |
| 599 | + const count = IDX_STATS_SESSION_DATAGRAMS_LOST + 1; |
| 600 | + const snapshot = new BigUint64Array(count); |
| 601 | + for (let i = 0; i < count; i++) { |
| 602 | + snapshot[i] = this.#handle[this.#offset + i]; |
| 603 | + } |
| 604 | + this.#handle = snapshot; |
| 605 | + this.#offset = 0; |
596 | 606 | this.#disconnected = true; |
597 | 607 | } |
598 | 608 | } |
599 | 609 |
|
600 | 610 | class QuicStreamStats { |
601 | 611 | /** @type {BigUint64Array} */ |
602 | 612 | #handle; |
| 613 | + /** @type {number} */ |
| 614 | + #offset = 0; |
603 | 615 | /** type {boolean} */ |
604 | 616 | #disconnected = false; |
605 | 617 |
|
606 | 618 | /** |
607 | 619 | * @param {symbol} privateSymbol |
608 | | - * @param {ArrayBuffer} buffer |
| 620 | + * @param {BigUint64Array|ArrayBuffer} view |
| 621 | + * @param {number} [byteOffset] - byte offset into the shared page view |
609 | 622 | */ |
610 | | - constructor(privateSymbol, buffer) { |
| 623 | + constructor(privateSymbol, view, byteOffset = 0) { |
611 | 624 | // We use the kPrivateConstructor symbol to restrict the ability to |
612 | 625 | // create new instances of QuicStreamStats to internal code. |
613 | 626 | if (privateSymbol !== kPrivateConstructor) { |
614 | 627 | throw new ERR_ILLEGAL_CONSTRUCTOR(); |
615 | 628 | } |
616 | | - if (!isArrayBuffer(buffer)) { |
617 | | - throw new ERR_INVALID_ARG_TYPE('buffer', ['ArrayBuffer'], buffer); |
| 629 | + if (isArrayBuffer(view)) { |
| 630 | + this.#handle = new BigUint64Array(view); |
| 631 | + } else { |
| 632 | + this.#handle = view; |
618 | 633 | } |
619 | | - this.#handle = new BigUint64Array(buffer); |
| 634 | + // Convert byte offset to element offset (8 bytes per uint64). |
| 635 | + this.#offset = byteOffset / 8; |
620 | 636 | } |
621 | 637 |
|
622 | 638 | /** @type {bigint} */ |
623 | 639 | get createdAt() { |
624 | | - return this.#handle[IDX_STATS_STREAM_CREATED_AT]; |
| 640 | + return this.#handle[this.#offset + IDX_STATS_STREAM_CREATED_AT]; |
625 | 641 | } |
626 | 642 |
|
627 | 643 | /** @type {bigint} */ |
628 | 644 | get openedAt() { |
629 | | - return this.#handle[IDX_STATS_STREAM_OPENED_AT]; |
| 645 | + return this.#handle[this.#offset + IDX_STATS_STREAM_OPENED_AT]; |
630 | 646 | } |
631 | 647 |
|
632 | 648 | /** @type {bigint} */ |
633 | 649 | get receivedAt() { |
634 | | - return this.#handle[IDX_STATS_STREAM_RECEIVED_AT]; |
| 650 | + return this.#handle[this.#offset + IDX_STATS_STREAM_RECEIVED_AT]; |
635 | 651 | } |
636 | 652 |
|
637 | 653 | /** @type {bigint} */ |
638 | 654 | get ackedAt() { |
639 | | - return this.#handle[IDX_STATS_STREAM_ACKED_AT]; |
| 655 | + return this.#handle[this.#offset + IDX_STATS_STREAM_ACKED_AT]; |
640 | 656 | } |
641 | 657 |
|
642 | 658 | /** @type {bigint} */ |
643 | 659 | get destroyedAt() { |
644 | | - return this.#handle[IDX_STATS_STREAM_DESTROYED_AT]; |
| 660 | + return this.#handle[this.#offset + IDX_STATS_STREAM_DESTROYED_AT]; |
645 | 661 | } |
646 | 662 |
|
647 | 663 | /** @type {bigint} */ |
648 | 664 | get bytesReceived() { |
649 | | - return this.#handle[IDX_STATS_STREAM_BYTES_RECEIVED]; |
| 665 | + return this.#handle[this.#offset + IDX_STATS_STREAM_BYTES_RECEIVED]; |
650 | 666 | } |
651 | 667 |
|
652 | 668 | /** @type {bigint} */ |
653 | 669 | get bytesSent() { |
654 | | - return this.#handle[IDX_STATS_STREAM_BYTES_SENT]; |
| 670 | + return this.#handle[this.#offset + IDX_STATS_STREAM_BYTES_SENT]; |
655 | 671 | } |
656 | 672 |
|
657 | 673 | /** @type {bigint} */ |
658 | 674 | get maxOffset() { |
659 | | - return this.#handle[IDX_STATS_STREAM_MAX_OFFSET]; |
| 675 | + return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET]; |
660 | 676 | } |
661 | 677 |
|
662 | 678 | /** @type {bigint} */ |
663 | 679 | get maxOffsetAcknowledged() { |
664 | | - return this.#handle[IDX_STATS_STREAM_MAX_OFFSET_ACK]; |
| 680 | + return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET_ACK]; |
665 | 681 | } |
666 | 682 |
|
667 | 683 | /** @type {bigint} */ |
668 | 684 | get maxOffsetReceived() { |
669 | | - return this.#handle[IDX_STATS_STREAM_MAX_OFFSET_RECV]; |
| 685 | + return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET_RECV]; |
670 | 686 | } |
671 | 687 |
|
672 | 688 | /** @type {bigint} */ |
673 | 689 | get finalSize() { |
674 | | - return this.#handle[IDX_STATS_STREAM_FINAL_SIZE]; |
| 690 | + return this.#handle[this.#offset + IDX_STATS_STREAM_FINAL_SIZE]; |
675 | 691 | } |
676 | 692 |
|
677 | 693 | toString() { |
@@ -735,9 +751,14 @@ class QuicStreamStats { |
735 | 751 | } |
736 | 752 |
|
737 | 753 | [kFinishClose]() { |
738 | | - // Snapshot the stats into a new BigUint64Array since the underlying |
739 | | - // buffer will be destroyed. |
740 | | - this.#handle = new BigUint64Array(this.#handle); |
| 754 | + // Snapshot this stream's stats slice into a standalone BigUint64Array. |
| 755 | + const count = IDX_STATS_STREAM_FINAL_SIZE + 1; |
| 756 | + const snapshot = new BigUint64Array(count); |
| 757 | + for (let i = 0; i < count; i++) { |
| 758 | + snapshot[i] = this.#handle[this.#offset + i]; |
| 759 | + } |
| 760 | + this.#handle = snapshot; |
| 761 | + this.#offset = 0; |
741 | 762 | this.#disconnected = true; |
742 | 763 | } |
743 | 764 | } |
|