Skip to content

Conversation

@tadjik1
Copy link
Member

@tadjik1 tadjik1 commented Nov 25, 2025

Description

Summary of Changes

Added a compare(a: Uint8Array, b: Uint8Array): -1 | 0 | 1 byte utility that performs a lexicographical comparison of two byte arrays.
Added a concat(list: Uint8Array[]): Uint8Array utility.

And mark ByteUtils as public and experimental (similar as for NumberUtils).

Notes for Reviewers
  • The comparison semantics for compare are intended to match typical lexicographical ordering used for binary data (byte-by-byte from index 0, with shorter equal-prefix arrays considered smaller).
  • concat is implemented using .length on Uint8Array (number of elements), which matches the number of bytes for this typed array and keeps the implementation simple and explicit.
  • Tests are designed to run in both Node and web environments, and assert the same outputs regardless of runtime.

What is the motivation for this change?

Release Highlight

Release notes highlight

ByteUtils are now public and provide set of platform-agnostic tools to manipulate binary data (using Buffer in nodejs-compatible environments and fallback to Uint8Array).

Double check the following

  • Lint is passing (npm run check:lint)
  • Self-review completed using the steps outlined here
  • PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • Changes are covered by tests
  • New TODOs have a related JIRA ticket

@tadjik1 tadjik1 force-pushed the NODE-7314 branch 2 times, most recently from 2379a1e to b5db818 Compare November 25, 2025 13:37
@tadjik1 tadjik1 marked this pull request as ready for review November 25, 2025 14:30
@tadjik1 tadjik1 requested a review from a team as a code owner November 25, 2025 14:30
@tadjik1 tadjik1 marked this pull request as draft November 25, 2025 15:46
@tadjik1 tadjik1 marked this pull request as ready for review November 25, 2025 16:34
Copy link
Contributor

@nbbeeken nbbeeken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, one concern:


concat(list: Uint8Array[]): Uint8Array {
if (list.length === 0) return webByteUtils.allocate(0);
if (list.length === 1) return list[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very clever optimization, but I wonder if returning the input instance could lead to small surprises when BSON is running using this "web mode" implementation.

In Node.js a copy to a new buffer is always performed

@baileympearson baileympearson self-assigned this Nov 25, 2025
@baileympearson baileympearson added the Primary Review In Review with primary reviewer, not yet ready for team's eyes label Nov 25, 2025
Copy link
Contributor

@baileympearson baileympearson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the AC in the ticket:

.isBuffer
Does not exist; but we'll either want to remove usages of this from the driver (we'll need to evaluate on a case-by-case basis) or use isUint8Array, which exists in BSON. Maybe it makes sense to export isUint8Array from BSON too.

and

.from
The driver uses Buffer.from to convert the following to buffers:

  • utf8 strings
  • number arrays
  • buffers
  • base64 strings
    Byte utils supports converting base64 strings and number arrays to Uint8Arrays already. converting buffers to buffers can be done using isUint8Array and conditionally converting the string argument to a buffer if needed. We will need to add conversion of utf8 strings -> buffers to byte utils.

Have you given these APIs thought / are they not needed to remove dependence on the global Buffer object in the driver?

return 0;
},

concat(list: Uint8Array[]): Uint8Array {
Copy link
Contributor

@baileympearson baileympearson Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
concat(list: Uint8Array[]): Uint8Array {
concat(uint8Arrays: Uint8Array[]): Uint8Array {

or

Suggested change
concat(list: Uint8Array[]): Uint8Array {
concat(arraysToConcat: Uint8Array[]): Uint8Array {

or something.

strive for as descriptive variable names as possible

const result = webByteUtils.allocate(totalLength);
let offset = 0;

for (const arr of list) {
Copy link
Contributor

@baileympearson baileympearson Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (const arr of list) {
for (const uint8Array of uint8Arrays) {

same as above

@Srolsper00
Copy link

/*

  • GRUB -- GRand Unified Bootloader
  • Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
  • GRUB is free software; you can redistribute it and/or modify
  • it under the terms of the GNU General Public License as published by
  • the Free Software Foundation; either version 3 of the License, or
  • (at your option) any later version.
  • GRUB is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.
  • You should have received a copy of the GNU General Public License
  • along with GRUB. If not, see http://www.gnu.org/licenses/.
    /
    /
  • Copyright 2010 Sun Microsystems, Inc. All rights reserved.
  • Use is subject to license terms.
    */

#ifndef _SYS_DNODE_H
#define _SYS_DNODE_H

#include <grub/zfs/spa.h>

/*

  • Fixed constants.
    /
    #define DNODE_SHIFT 9 /
    512 bytes /
    #define DN_MIN_INDBLKSHIFT 10 /
    1k /
    #define DNODE_BLOCK_SHIFT 14 /
    16k /
    #define DNODE_CORE_SIZE 64 /
    64 bytes for dnode sans blkptrs */

/*

  • Derived constants.
    */
    #define DNODE_SIZE (1 << DNODE_SHIFT)
    #define DN_MAX_NBLKPTR ((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
    #define DN_MAX_BONUSLEN (DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT))

#define DNODES_PER_BLOCK_SHIFT (DNODE_BLOCK_SHIFT - DNODE_SHIFT)
#define DNODES_PER_BLOCK (1ULL << DNODES_PER_BLOCK_SHIFT)

#define DNODE_FLAG_SPILL_BLKPTR (1<<2)

#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus +
(((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))

typedef struct dnode_phys {
grub_uint8_t dn_type; /* dmu_object_type_t /
grub_uint8_t dn_indblkshift; /
ln2(indirect block size) /
grub_uint8_t dn_nlevels; /
1=dn_blkptr->data blocks /
grub_uint8_t dn_nblkptr; /
length of dn_blkptr /
grub_uint8_t dn_bonustype; /
type of data in bonus buffer /
grub_uint8_t dn_checksum; /
ZIO_CHECKSUM type /
grub_uint8_t dn_compress; /
ZIO_COMPRESS type /
grub_uint8_t dn_flags; /
DNODE_FLAG_* /
grub_uint16_t dn_datablkszsec; /
data block size in 512b sectors /
grub_uint16_t dn_bonuslen; /
length of dn_bonus */
grub_uint8_t dn_pad2[4];

/* accounting is protected by dn_dirty_mtx */
grub_uint64_t dn_maxblkid;		/* largest allocated block ID */
grub_uint64_t dn_used;		/* bytes (or sectors) of disk space */

grub_uint64_t dn_pad3[4];

blkptr_t dn_blkptr[1];
grub_uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)];
blkptr_t dn_spill;

} dnode_phys_t;

#endif /* _SYS_DNODE_H */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Primary Review In Review with primary reviewer, not yet ready for team's eyes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants