HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
ronomon
hash-table
JavaScript2018–2020
ronomon / hash-table

hash-table

Fast, reliable cuckoo hash table for Node.js.

3Distinct people
14Mentions
1Explicit recommenders
304GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Fast, reliable cuckoo hash table for Node.js.

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

One of the things I love about JavaScript is that you can write an almost 10x faster hash table than the standard library if you take care of cache misses and GC:…

_urga used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:03:16 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by month14 dated mentions

Observed mentions: 2018-09-06 16:15:55 UTC to 2020-06-17 21:40:41 UTC.

01232018-09-01 00:00:00 UTC to 2018-10-01 00:00:00 UTC (exclusive): 3 mentions; 2 submissions, 1 commentsSep 20182018-10-01 00:00:00 UTC to 2018-11-01 00:00:00 UTC (exclusive): 3 mentions; 1 submissions, 2 comments2018-11-01 00:00:00 UTC to 2018-12-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-12-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-01-01 00:00:00 UTC to 2019-02-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-02-01 00:00:00 UTC to 2019-03-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-03-01 00:00:00 UTC to 2019-04-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-04-01 00:00:00 UTC to 2019-05-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-05-01 00:00:00 UTC to 2019-06-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-06-01 00:00:00 UTC to 2019-07-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-07-01 00:00:00 UTC to 2019-08-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 commentsJul 20192019-08-01 00:00:00 UTC to 2019-09-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-09-01 00:00:00 UTC to 2019-10-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments2019-10-01 00:00:00 UTC to 2019-11-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-11-01 00:00:00 UTC to 2019-12-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-12-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2020-02-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-02-01 00:00:00 UTC to 2020-03-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-03-01 00:00:00 UTC to 2020-04-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-04-01 00:00:00 UTC to 2020-05-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-05-01 00:00:00 UTC to 2020-06-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-06-01 00:00:00 UTC to 2020-07-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 commentsJun 2020

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
Sep 20182018-09-01 00:00:00 UTC2018-10-01 00:00:00 UTC321
Oct 20182018-10-01 00:00:00 UTC2018-11-01 00:00:00 UTC312
Nov 20182018-11-01 00:00:00 UTC2018-12-01 00:00:00 UTC000
Dec 20182018-12-01 00:00:00 UTC2019-01-01 00:00:00 UTC101
Jan 20192019-01-01 00:00:00 UTC2019-02-01 00:00:00 UTC000
Feb 20192019-02-01 00:00:00 UTC2019-03-01 00:00:00 UTC101
Mar 20192019-03-01 00:00:00 UTC2019-04-01 00:00:00 UTC101
Apr 20192019-04-01 00:00:00 UTC2019-05-01 00:00:00 UTC000
May 20192019-05-01 00:00:00 UTC2019-06-01 00:00:00 UTC000
Jun 20192019-06-01 00:00:00 UTC2019-07-01 00:00:00 UTC000
Jul 20192019-07-01 00:00:00 UTC2019-08-01 00:00:00 UTC000
Aug 20192019-08-01 00:00:00 UTC2019-09-01 00:00:00 UTC000
Sep 20192019-09-01 00:00:00 UTC2019-10-01 00:00:00 UTC110
Oct 20192019-10-01 00:00:00 UTC2019-11-01 00:00:00 UTC000
Nov 20192019-11-01 00:00:00 UTC2019-12-01 00:00:00 UTC000
Dec 20192019-12-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
Jan 20202020-01-01 00:00:00 UTC2020-02-01 00:00:00 UTC000
Feb 20202020-02-01 00:00:00 UTC2020-03-01 00:00:00 UTC000
Mar 20202020-03-01 00:00:00 UTC2020-04-01 00:00:00 UTC101
Apr 20202020-04-01 00:00:00 UTC2020-05-01 00:00:00 UTC000
May 20202020-05-01 00:00:00 UTC2020-06-01 00:00:00 UTC101
Jun 20202020-06-01 00:00:00 UTC2020-07-01 00:00:00 UTC202

What Hacker News says

14 sources
_urga·Jun 17, 2020Recommendation phrase
One of the things I love about JavaScript is that you can write an almost 10x faster hash table than the standard library if you take care of cache misses and GC: https://github.com/ronomon/hash-table#motivation In fact, all the usual low-level optimization techniques like reducing branch mispredictions and expensive memory accesses apply, and make a huge difference, even though you're writing in a high-level language.
In Deep JavaScript: Theory and Techniques
> Finding ways to have, say, 10 million blacklist elements with a small memory footprint is left as an exercise for the reader. In case the reader is interested (and this may not be what OP had in mind): In trading memory gains with computation, this is how I squeezed ~4M entries in less than 30 MiB: 1. Compress (reversed) individual entries using a dictionary or entropy encoder. I experimented with Shoco [0], Femto [1], and a modified LZ78 [2]. 2. Create a bloom filter for membership checks, [3] or any probabilistic structure for that matter, like the xor-filters [4]. This prevents expensive but unnecessary lookups. 3. Insert the compressed (reversed: google.com -> com.google) entries into a radix-tree [5]. You could use a directed-acyclic graph (DAG), if you don't need to store key-value pairs. 4. Compact [6][7] the radix-tree [8] (comp
Read the rest
acting a DAG might be super complicated). 5. On every search: 5a. Compress (reversed) incoming query (i.e. domain-name). 5b. Check the bloom filter. 5c. Traverse the radix-tree, if necessary. 5d. Cache an eligible entry in a LFU [9] or possibly, using any other suitable algorithm inspired from Linux's page replacement implementations [10]. 6. Strive for zero-allocation and zero-gc. --- [0] https://news.ycombinator.com/item?id=10060018 [1] https://github.com/gtoubassi/femtozip/wiki/How-femtozip-work... [2] https://en.wikipedia.org/wiki/LZ78 [3] https://news.ycombinator.com/item?id=12231623 [4] https://news.ycombinator.com/item?id=21840821 [5] https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-lin... [6] https://news.ycombinator.com/item?id=22544718 [7] https://www.youtube-nocookie.com/embed/3Y2weLDiUWw [8] https://news.ycombinator.com/item?id=2348619 [9] https://github.com/ronomon/hash-table/blob/master/README.md [10] https://en.wikipedia.org/wiki/Page_replacement_algorithm
In Ad blocking with Raspberry Pi and Pi-hole
I've come across a fair share of zero-alloc implementations of various things, like u/poitrus' zerolog [0] and u/jorangreef's cuckoo-hashtable [1], for instance. Given that JavaScript runs on restrictive clients, it must have libraries in spades for this kind of a thing, but I couldn't find many. I'm really interested in techniques that are generally employed in languages like Java, Golang, Rust, C/++ that are worth translating over to JavaScript, especially now that TypedArrays are a reality. I'm pretty sure there's more to zero-alloc than just Buffers, Object pools, and Recyclables, but I can't seem to find good resources to get started with this. [0] https://github.com/rs/zerolog [1] https://github.com/ronomon/hash-table/blob/master/README.md
In Show HN: Molecule – Streaming, zero-allocation protobuf decoding in Go
"If memory overhead (load factor) isn't a big issue, readers may also find cuckoo hashing rather interesting." The issue with memory overhead (load factor) is actually something that Cuckoo hashing solves compared to linear probing. Bucketized Cuckoo hashing supports much higher load factors than linear probing. You can have your cake and eat it too. I have implemented hash tables with open addressing and tombstones in the past (linear probing, triangular probing etc.) and I much prefer Cuckoo hashing now. When Cuckoo hashing is combined with a bloom filter in the first position to reduce cache misses to the second position, it's almost perfect in every way: fast (drastically reduced cache misses), constant lookup time in the worst case (not so for linear probing), higher load factors (80% or more for Cuckoo hashing vs at most 50% for lin
Read the rest
ear probing - this also affects amortized resize latency), not to mention elegant simplicity. In case anyone is interested, here are some design details and decisions for an optimized bucketized Cuckoo hash table with bloom filters implemented for Node.js: https://github.com/ronomon/hash-table
In Why Hashbrown Does a Double Lookup
The comparison between the classes of "Las Vegas" and "Monte Carlo" algorithms is a useful distinction, along with the author's suggestion of using a cache table as a lookup table for compression match finding. If anyone is interested, I wrote @ronomon/hash-table as a fast, scalable cuckoo hash table for Node.js. It has high load factor, constant lookup time in the worst-case and uses a non-recursive variant of the cuckoo probing scheme, together with a bloom filter to reduce cache misses to the alternative cuckoo bucket by an order of magnitude. Last but not least, caching is supported according to the CLOCK LRU algorithm, which is elegant and effective. Benchmarks and design decisions are in the README: https://github.com/ronomon/hash-table
In Cache tables
This is a fantastic explanation of developments in hash tables in general. If anyone is interested, I recently released a scalable hash table for Node.js (@ronomon/hash-table), designed to store literally billions of elements without stressing the GC. At first, I tried writing a native addon module for Node.js in C (using SIMD), but the Javascript-to-C call cost was just too high, and doubled latency. In the end, I was surprised to find that writing directly in Javascript proved faster than the C module with SIMD, simply by avoiding the bridging cost. Also, instead of linear or quadratic probing (or double hashing or triangular probing), I used cuckoo hashing, but with a twist. Normally, in the case of a naive cuckoo hash table, if an element is not in its first bucket, then its second bucket must be fetched from memory, causing a cache m
Read the rest
iss, which for a hash table is embarrassingly slow. This is why SwissTable and F14 tend to avoid naive cuckoo hashing. However, in our design, the first bucket includes an 8-byte coarse-grained bloom filter (k=1, or a single bit per element). If the element is not in this bloom filter, the element is guaranteed not to be in either of its first or second buckets, and a cache miss can be avoided nearly 90% of the time. Using cuckoo hashing in this way then starts to produce major advantages over linear probing: no tombstones, higher load factor (which has knock-on implications for resize latency), and constant time worst-case lookups. More design details are here: https://github.com/ronomon/hash-table
In The Swiss Army Knife of Hashmaps
I recently finished a scalable hash table for Node.js, designed to store billions of elements in huge flat buffers without impacting the garbage collector (no pointer chasing), and without causing memory fragmentation. At first, I tried a native add-on, using SIMD instructions to compare multiple keys per instruction. This makes the use of buckets (multiple keys per slot) compelling, because the branching cost of key comparisons almost disappears. However, in the end, the 100ns to 200ns cost of calling into C from Javascript using N-API (or V8) mitigated any SIMD gains, so I rewrote the hash table in Javascript directly. While not as fast as a pure C implementation, it's still fairly fast, and more scalable than Javascript's native vanilla objects, Sets or Maps. The notes on design and optimization decisions taken are here, if anyone is i
Read the rest
In Swiss Tables and absl::Hash
Thanks, I added Set into the rough vanilla comparison. It's slightly better than a vanilla object, but it's still almost an order of magnitude slower, and is most likely still going to have issues with GC overhead when storing millions of pointers. GC issues blocking the event loop are not fun when you have a hash table with billions of elements. Also, while a Set can technically receive an Array (or iterable) upfront in the constructor, this requires you to have your Array available upfront, which is not always the case, and an Array is also not meant for millions of objects in the first place. For example, AFAIK (and I may be wrong since last I checked) but V8's Array will switch mode and degrade into an object at around 10,000 elements. So with Set (or Map) there's still no production-quality way to allocate and reserve capacity upfron
Read the rest
t by the number of elements or size in bytes. Please note, the `vanilla.js` comparison in the Motivation section is not meant as a benchmark, but just to sketch the principles outlined there. You don't actually even see the 10× differential with `vanilla.js` because it only inserts 4,000,000 elements - I would have set it higher but Set and Object start taking forever or cause OOM crashes beyond that. More accurate, in-depth performance numbers are here: https://github.com/ronomon/hash-table#performance
In A 10× Faster Hash Table for Node.js

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.