1.3.9 • Published 1 year ago

msgpack-nodejs v1.3.9

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

msgpack-nodejs

GitHub Workflow Status Vulnerabilities node-current GitHub top language Lines of code npm bundle size

Yet another javascript/nodejs implementation of MsgPack Spec.
The purpose behind is learning by doing, which focuses on modern tools/techniques of nodejs/typescript ecosystem.

Contents


Usage

npm i msgpack-nodejs
npm test

Example

Please check example.md

API

  1. encode(): any => Uint8Array
  2. decode(): Uint8Array => Exclude<any, Map>
  3. EncodeStream class: Exclude<any, null> => Buffer
  4. DecodeStream class: Buffer => Exclude<any, null> ^1
  5. registerExtension(): Register your own extension
  6. stringBufferStat(): Show string buffer copied count and size
  7. lruCacheStat(): Show cache hit/miss count
  8. bufferAllocatorStat(): Show how byte-array allocate new buffer
  9. prefixTrieStat(): Show prefix-trie hit/miss count
  10. applyOptions(): Manually control caching

^1: After attaching another stream that does not expect a object as its input, you may encounter error

Options

You can apply options like this

KeytypedefaultDescription
encoder.mapKeyCache.enabledbooleantrueCache map-key or not
encoder.mapKeyCache.sizenumber30How big is the mapKeyCache
encoder.stringCache.enabledbooleantrueCache any string except map-key or not
encoder.stringCache.sizenumber100How big is the stringCache
encoder.byteArray.basenumber1024How many bytes will be allocated for every execution. Setting this would increase performance when handling many big JSON data
decoder.shortStringCache.enabledbooleantrueUse prefix-trie or not
decoder.shortStringCache.lessThannumber10Only cache if string is shorter than this value
decoder.jsUtf8Decode.enabledbooleantrueUse JS utf8-decode or not
decoder.jsUtf8Decode.lessThannumber200Only use JS utf8-decode if string is shorter than this value

Project status

Compability

EnvExecutable?
Node.js 18
Node.js 16
Node.js 14
Node.js 12

Limitation

  1. Does not support float 32 encoding, because Javascript float is always 64-bit.

TODO

  1. Ext tests
  2. Map 16/32 tests

Benchmark

By utlizing the great benchmark tool by msgpack-lite, I thought the performance of this project would not be disappointing.

Runs on node.js 16 & laptop with R5-5625U.

operationopmsop/s
buf = Buffer(JSON.stringify(obj));10212005000204240
obj = JSON.parse(buf);12795005000255900
buf = require("msgpack-lite").encode(obj);6858005000137160
obj = require("msgpack-lite").decode(buf);389800500177944
buf = Buffer(require("msgpack.codec").msgpack.pack(obj));7136005000142720
obj = require("msgpack.codec").msgpack.unpack(buf);401300500180243
buf = require("msgpack-js-v5").encode(obj);284400500056880
obj = require("msgpack-js-v5").decode(buf);5446005000108920
buf = require("msgpack-js").encode(obj);277100500155408
obj = require("msgpack-js").decode(buf);5598005000111960
buf = require("msgpack5")().encode(obj);147700500129534
obj = require("msgpack5")().decode(buf);239500500047900
buf = require("notepack").encode(obj);10415005000208300
obj = require("notepack").decode(buf);6713005000134260
obj = require("msgpack-unpack").decode(buf);163400500132673
buf = require("msgpack-nodejs").encode(obj); (Run in sequence)11489005000229780
obj = require("msgpack-nodejs").decode(buf); (Run in sequence)7775005000155500
buf = require("msgpack-nodejs").encode(obj); (Run exclusively)13219005000264380
obj = require("msgpack-nodejs").decode(buf); (Run exclusively)8054005000161080

Implementation detail

Encode

Encoder uses a recursive function match() to match JSON structure (primitive value, object, array or nested), and pushes anything encoded into ByteArray that responsible for allocating buffer. Encoded string will be written in StringBuffer first and cached in LruCache.

Decode

Decoder uses parseBuffer() to read every value out, and push them into StructBuilder to rebuild whole JSON object. For string less than 200 bytes, use pure JS utf8Decode(), then cache in prefix trie.

Optimization strategies:

Cache
  • To improve encoding performance, LruCache was used for caching encoded string and its header.
  • To improve decoding peformance, prefix trie was deployed for Uint8Array caching.
  • To avoid evicting, map-key caching and string caching were separated.
ArrayBuffer / TypedArray
  • To efficiently allocate new buffer, every ByteArray begins with small buffer (1K). ^2
  • To efficiently handle unpredictable large JSON, ByteArray allocates exponentially.
  • To avoid overhead on writing, ByteArray uses DataView calls as much as possible.
Node.js

Lessons learned

  • Javascript
    • The difference between ArrayBuffer, TypedArray and the node.js API Buffer ^5
    • BigInt operators ^6
    • left shift and right shift ^7
    • Private class features ^9
    • Pre-allocated array ^3
    • UTF-8 encoding/decoding ^10
    • Node.js transform stream ^11
  • Node.js
  • Typescript
    • Testing - ts-jest ^13
    • Linter - typescript-eslint & lint-staged ^14
    • Packaging for ESModule & CommonJS ^15
  • CI & CD
    • Github Actions ^16

^2: Thanks to kriszyp/msgpackr for inspiration of better buffer allocation strategy. ^3: Thanks to AppSpector, this article gives very practical advices including pre-allocated array and manual decoding under 200 characters. ^4: Thanks to msgpack/msgpack-javascript for technique including UTF-8 bytes calculation and usage of encodeInto(), which led me to the ultra optimization strategy. ^5: [JS] TypedArray, ArrayBuffer 和 DataView ^6: BigInt operators ^7: left shift ^8: right shift ^9: Private class features ^10: UTF-8 encoding/decoding ^11: samerbuna/efficient-node ^12: Profiler ^13: ts-jest ^14: 使用 ESLint, Prettier, Husky, Lint-staged 以及 Commitizen 提升專案品質及一致性 ^15: Best practices for creating a modern npm package ^16: Github Actions ^17: Memory Diagnostics - Using GC Trace

1.3.7

1 year ago

1.3.6

1 year ago

1.3.9

1 year ago

1.3.8

1 year ago

1.3.5

1 year ago

1.3.4

1 year ago

1.3.3

1 year ago

1.3.2

1 year ago

1.3.1

1 year ago

1.3.0

1 year ago

1.2.0

1 year ago

1.1.0

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago