From a361e29a68bbad78318715e6aee696f0006f4b34 Mon Sep 17 00:00:00 2001 From: awwit <ignatius.awwit@gmail.com> Date: Fri, 22 May 2020 00:33:21 +0300 Subject: [PATCH 1/3] feat: slightly improved v1 perf --- examples/benchmark/benchmark.js | 8 ++++++- src/bytesToUuid.js | 42 +++++++++++++++------------------ src/v1.js | 8 +++++-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/examples/benchmark/benchmark.js b/examples/benchmark/benchmark.js index b62b16ae..0c713c75 100644 --- a/examples/benchmark/benchmark.js +++ b/examples/benchmark/benchmark.js @@ -21,7 +21,13 @@ suite uuidv1(); }) .add('uuidv1() fill existing array', function () { - uuidv1(null, array, 0); + try { + uuidv1(null, array, 0); + } catch (err) { + if (err.code !== 'UUID_V1_LIMIT_PER_SEC') { + throw err; + } + } }) .add('uuidv4()', function () { uuidv4(); diff --git a/src/bytesToUuid.js b/src/bytesToUuid.js index 7e90bdb9..dd95b87a 100644 --- a/src/bytesToUuid.js +++ b/src/bytesToUuid.js @@ -2,40 +2,36 @@ * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ -const byteToHex = []; +const bth = []; for (let i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); + bth.push((i + 0x100).toString(16).substr(1)); } -function bytesToUuid(buf, offset) { - const i = offset || 0; - - const bth = byteToHex; - +function bytesToUuid(buf, offset = 0) { // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 return ( - bth[buf[i + 0]] + - bth[buf[i + 1]] + - bth[buf[i + 2]] + - bth[buf[i + 3]] + + bth[buf[offset + 0]] + + bth[buf[offset + 1]] + + bth[buf[offset + 2]] + + bth[buf[offset + 3]] + '-' + - bth[buf[i + 4]] + - bth[buf[i + 5]] + + bth[buf[offset + 4]] + + bth[buf[offset + 5]] + '-' + - bth[buf[i + 6]] + - bth[buf[i + 7]] + + bth[buf[offset + 6]] + + bth[buf[offset + 7]] + '-' + - bth[buf[i + 8]] + - bth[buf[i + 9]] + + bth[buf[offset + 8]] + + bth[buf[offset + 9]] + '-' + - bth[buf[i + 10]] + - bth[buf[i + 11]] + - bth[buf[i + 12]] + - bth[buf[i + 13]] + - bth[buf[i + 14]] + - bth[buf[i + 15]] + bth[buf[offset + 10]] + + bth[buf[offset + 11]] + + bth[buf[offset + 12]] + + bth[buf[offset + 13]] + + bth[buf[offset + 14]] + + bth[buf[offset + 15]] ).toLowerCase(); } diff --git a/src/v1.js b/src/v1.js index 52a49f54..0c485810 100644 --- a/src/v1.js +++ b/src/v1.js @@ -16,7 +16,7 @@ let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details function v1(options, buf, offset) { let i = (buf && offset) || 0; - const b = buf || []; + const b = buf || new Array(16); options = options || {}; let node = options.node || _nodeId; @@ -27,6 +27,7 @@ function v1(options, buf, offset) { // system entropy. See #189 if (node == null || clockseq == null) { const seedBytes = options.random || (options.rng || rng)(); + if (node == null) { // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) node = _nodeId = [ @@ -38,6 +39,7 @@ function v1(options, buf, offset) { seedBytes[5], ]; } + if (clockseq == null) { // Per 4.2.2, randomize (14 bit) clockseq clockseq = _clockseq = ((seedBytes[6] << 8) | seedBytes[7]) & 0x3fff; @@ -70,7 +72,9 @@ function v1(options, buf, offset) { // Per 4.2.1.2 Throw error if too many uuids are requested if (nsecs >= 10000) { - throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + const error = new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + error.code = 'UUID_V1_LIMIT_PER_SEC'; + throw error; } _lastMSecs = msecs; From 056d3e32f78dddceadc810ec73315c5b85253d88 Mon Sep 17 00:00:00 2001 From: awwit <ignatius.awwit@gmail.com> Date: Mon, 25 May 2020 15:25:45 +0300 Subject: [PATCH 2/3] revert: throw original Error --- .eslintrc.json | 8 +++++++- examples/benchmark/benchmark.js | 6 +----- src/bytesToUuid.js | 36 ++++++++++++++++----------------- src/v1.js | 4 +--- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index cd838aeb..4b2152a0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,6 +13,12 @@ }, "parser": "babel-eslint", "rules": { - "no-var": ["error"] + "no-var": ["error"], + "no-empty": [ + "error", + { + "allowEmptyCatch": true + } + ] } } diff --git a/examples/benchmark/benchmark.js b/examples/benchmark/benchmark.js index 0c713c75..cf4de836 100644 --- a/examples/benchmark/benchmark.js +++ b/examples/benchmark/benchmark.js @@ -23,11 +23,7 @@ suite .add('uuidv1() fill existing array', function () { try { uuidv1(null, array, 0); - } catch (err) { - if (err.code !== 'UUID_V1_LIMIT_PER_SEC') { - throw err; - } - } + } catch (err) {} }) .add('uuidv4()', function () { uuidv4(); diff --git a/src/bytesToUuid.js b/src/bytesToUuid.js index dd95b87a..0c27824b 100644 --- a/src/bytesToUuid.js +++ b/src/bytesToUuid.js @@ -2,36 +2,36 @@ * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ -const bth = []; +const byteToHex = []; for (let i = 0; i < 256; ++i) { - bth.push((i + 0x100).toString(16).substr(1)); + byteToHex.push((i + 0x100).toString(16).substr(1)); } function bytesToUuid(buf, offset = 0) { // Note: Be careful editing this code! It's been tuned for performance // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 return ( - bth[buf[offset + 0]] + - bth[buf[offset + 1]] + - bth[buf[offset + 2]] + - bth[buf[offset + 3]] + + byteToHex[buf[offset + 0]] + + byteToHex[buf[offset + 1]] + + byteToHex[buf[offset + 2]] + + byteToHex[buf[offset + 3]] + '-' + - bth[buf[offset + 4]] + - bth[buf[offset + 5]] + + byteToHex[buf[offset + 4]] + + byteToHex[buf[offset + 5]] + '-' + - bth[buf[offset + 6]] + - bth[buf[offset + 7]] + + byteToHex[buf[offset + 6]] + + byteToHex[buf[offset + 7]] + '-' + - bth[buf[offset + 8]] + - bth[buf[offset + 9]] + + byteToHex[buf[offset + 8]] + + byteToHex[buf[offset + 9]] + '-' + - bth[buf[offset + 10]] + - bth[buf[offset + 11]] + - bth[buf[offset + 12]] + - bth[buf[offset + 13]] + - bth[buf[offset + 14]] + - bth[buf[offset + 15]] + byteToHex[buf[offset + 10]] + + byteToHex[buf[offset + 11]] + + byteToHex[buf[offset + 12]] + + byteToHex[buf[offset + 13]] + + byteToHex[buf[offset + 14]] + + byteToHex[buf[offset + 15]] ).toLowerCase(); } diff --git a/src/v1.js b/src/v1.js index 0c485810..dbf4f5ca 100644 --- a/src/v1.js +++ b/src/v1.js @@ -72,9 +72,7 @@ function v1(options, buf, offset) { // Per 4.2.1.2 Throw error if too many uuids are requested if (nsecs >= 10000) { - const error = new Error("uuid.v1(): Can't create more than 10M uuids/sec"); - error.code = 'UUID_V1_LIMIT_PER_SEC'; - throw error; + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); } _lastMSecs = msecs; From 1b158ff41d055913d4c3548eefb10ca4d72a99ba Mon Sep 17 00:00:00 2001 From: awwit <ignatius.awwit@gmail.com> Date: Mon, 25 May 2020 18:41:47 +0300 Subject: [PATCH 3/3] test: added comment for v1 in benchmark --- .eslintrc.json | 8 +------- examples/benchmark/benchmark.js | 6 +++++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 4b2152a0..cd838aeb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,12 +13,6 @@ }, "parser": "babel-eslint", "rules": { - "no-var": ["error"], - "no-empty": [ - "error", - { - "allowEmptyCatch": true - } - ] + "no-var": ["error"] } } diff --git a/examples/benchmark/benchmark.js b/examples/benchmark/benchmark.js index cf4de836..dc3ff19f 100644 --- a/examples/benchmark/benchmark.js +++ b/examples/benchmark/benchmark.js @@ -23,7 +23,11 @@ suite .add('uuidv1() fill existing array', function () { try { uuidv1(null, array, 0); - } catch (err) {} + } catch (err) { + // The spec (https://tools.ietf.org/html/rfc4122#section-4.2.1.2) defines that only 10M/s v1 + // UUIDs can be generated on a single node. This library throws an error if we hit that limit + // (which can happen on modern hardware and modern Node.js versions). + } }) .add('uuidv4()', function () { uuidv4();