HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
sirgallo
cmapv2
Go2025–2025
sirgallo / cmapv2

cmapv2

a concurrent hash array mapped trie implementation in go

2Distinct people
4Mentions
0Explicit recommenders
56GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

a concurrent hash array mapped trie implementation in go

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

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:56:07 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 3-hour interval4 dated mentions

Observed mentions: 2025-06-16 01:00:15 UTC to 2025-06-19 16:44:10 UTC.

0122025-06-16 00:00:00 UTC to 2025-06-16 03:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 commentsJun 16, 00:002025-06-16 03:00:00 UTC to 2025-06-16 06:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 06:00:00 UTC to 2025-06-16 09:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 09:00:00 UTC to 2025-06-16 12:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 12:00:00 UTC to 2025-06-16 15:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 15:00:00 UTC to 2025-06-16 18:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 18:00:00 UTC to 2025-06-16 21:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-16 21:00:00 UTC to 2025-06-17 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 00:00:00 UTC to 2025-06-17 03:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 03:00:00 UTC to 2025-06-17 06:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 06:00:00 UTC to 2025-06-17 09:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 09:00:00 UTC to 2025-06-17 12:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 12:00:00 UTC to 2025-06-17 15:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 15:00:00 UTC to 2025-06-17 18:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-17 18:00:00 UTC to 2025-06-17 21:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 commentsJun 17, 18:002025-06-17 21:00:00 UTC to 2025-06-18 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 00:00:00 UTC to 2025-06-18 03:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 03:00:00 UTC to 2025-06-18 06:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 06:00:00 UTC to 2025-06-18 09:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 09:00:00 UTC to 2025-06-18 12:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 12:00:00 UTC to 2025-06-18 15:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 15:00:00 UTC to 2025-06-18 18:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 18:00:00 UTC to 2025-06-18 21:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-18 21:00:00 UTC to 2025-06-19 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 00:00:00 UTC to 2025-06-19 03:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 03:00:00 UTC to 2025-06-19 06:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 06:00:00 UTC to 2025-06-19 09:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 09:00:00 UTC to 2025-06-19 12:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 12:00:00 UTC to 2025-06-19 15:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-06-19 15:00:00 UTC to 2025-06-19 18:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 commentsJun 19, 15:00

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
Jun 16, 00:002025-06-16 00:00:00 UTC2025-06-16 03:00:00 UTC110
Jun 16, 03:002025-06-16 03:00:00 UTC2025-06-16 06:00:00 UTC000
Jun 16, 06:002025-06-16 06:00:00 UTC2025-06-16 09:00:00 UTC000
Jun 16, 09:002025-06-16 09:00:00 UTC2025-06-16 12:00:00 UTC000
Jun 16, 12:002025-06-16 12:00:00 UTC2025-06-16 15:00:00 UTC000
Jun 16, 15:002025-06-16 15:00:00 UTC2025-06-16 18:00:00 UTC000
Jun 16, 18:002025-06-16 18:00:00 UTC2025-06-16 21:00:00 UTC000
Jun 16, 21:002025-06-16 21:00:00 UTC2025-06-17 00:00:00 UTC000
Jun 17, 00:002025-06-17 00:00:00 UTC2025-06-17 03:00:00 UTC000
Jun 17, 03:002025-06-17 03:00:00 UTC2025-06-17 06:00:00 UTC000
Jun 17, 06:002025-06-17 06:00:00 UTC2025-06-17 09:00:00 UTC000
Jun 17, 09:002025-06-17 09:00:00 UTC2025-06-17 12:00:00 UTC000
Jun 17, 12:002025-06-17 12:00:00 UTC2025-06-17 15:00:00 UTC000
Jun 17, 15:002025-06-17 15:00:00 UTC2025-06-17 18:00:00 UTC000
Jun 17, 18:002025-06-17 18:00:00 UTC2025-06-17 21:00:00 UTC202
Jun 17, 21:002025-06-17 21:00:00 UTC2025-06-18 00:00:00 UTC000
Jun 18, 00:002025-06-18 00:00:00 UTC2025-06-18 03:00:00 UTC000
Jun 18, 03:002025-06-18 03:00:00 UTC2025-06-18 06:00:00 UTC000
Jun 18, 06:002025-06-18 06:00:00 UTC2025-06-18 09:00:00 UTC000
Jun 18, 09:002025-06-18 09:00:00 UTC2025-06-18 12:00:00 UTC000
Jun 18, 12:002025-06-18 12:00:00 UTC2025-06-18 15:00:00 UTC000
Jun 18, 15:002025-06-18 15:00:00 UTC2025-06-18 18:00:00 UTC000
Jun 18, 18:002025-06-18 18:00:00 UTC2025-06-18 21:00:00 UTC000
Jun 18, 21:002025-06-18 21:00:00 UTC2025-06-19 00:00:00 UTC000
Jun 19, 00:002025-06-19 00:00:00 UTC2025-06-19 03:00:00 UTC000
Jun 19, 03:002025-06-19 03:00:00 UTC2025-06-19 06:00:00 UTC000
Jun 19, 06:002025-06-19 06:00:00 UTC2025-06-19 09:00:00 UTC000
Jun 19, 09:002025-06-19 09:00:00 UTC2025-06-19 12:00:00 UTC000
Jun 19, 12:002025-06-19 12:00:00 UTC2025-06-19 15:00:00 UTC000
Jun 19, 15:002025-06-19 15:00:00 UTC2025-06-19 18:00:00 UTC101

What Hacker News says

4 sources
The point of enumerating all of those specific issues, wasn't to say "here are some bugs" and if you fix them you're good. It was to say "here are some examples of the much more fundamental problem", which seemed to be a fundamental misunderstanding of the language memory model and the guarantees offered by assignments, atomic.CompareAndSwap, etc., and those operations' interactions with package unsafe. For example this code https://github.com/sirgallo/cmapv2/blob/6bcaa0253b1b0b261e8a... and in particular its use of this code https://github.com/sirgallo/cmapv2/blob/6bcaa0253b1b0b261e8a... is still completely unsound. Looking at *only this code path* -- and there are *many more* -- --- Put - Snapshots the current root pointer with atomic.LoadPointer - Makes an updated root pointer via putRecursive, given the snapshotted root pointer - Spin
Read the rest
s on a CAS of the root ptr and the updated ptr with runtime.Gosched() between attempts --- atomic.LoadPointer isn't a real snapshot - It's atomic only over the root ptr, not any interior field - Those interior fields are mutated in-place via e.g. setBitmap, setChild, etc. - Any goroutine can see partial data, violating the memory model, etc. --- putRecursive is unsound - copyNode performs a shallow copy, child pointers are shared, subsequent setChild, extendTable, etc. mutate nodes other goroutines can still hold -- this is a fundamental bug that seems to remain un-addressed from the previous review - Those mutations use plain writes (no atomics/locks/etc.) -- data race, memory model violation, etc. - Get later returns the internal []byte slice directly -- data race, memory model violation, etc. - Newly created nodes are cast to unsafe.Pointer without an atomic store, bypassing the write barrier required by the GC --- That compareAndSwap is unsound - It compares only the root pointer, a shallow copy - After a successful CAS other writers can still mutate any shared children (see above), so readers following any shared path see data races, memory model violations, etc. - The retry loop can livelock, details elided --- The implementation still seems to confuse "atomic pointer swap" with "atomic update of a complex, shared value", misunderstands the requirements of the Go memory model, and consistently mis-uses unsafe.Pointer. tl;dr here is probably to just stop using package unsafe altogether, until you have some time to properly understand its semantics, requirements, and limitations...
In Cmapv2: A high performance, concurrent map
Be more specific? OK --- CopyNode broken `CopyNode` duplicates only the parent; every child pointer is still shared nodeCopy.setChildren(make([]*node, len(n.children))) copy(nodeCopy.children, n.children) // pointers reused https://github.com/sirgallo/cmapv2/blob/main/node.go#L11-L17 Any later mutation (for example `setValue`) writes through those shared pointers, so readers and historical snapshots are modified concurrently -- invalid, data race, memory model violation --- Bitmap corruption `SetBit` uses XOR rather than “set”: func SetBit(bitmap uint32, position int) uint32 { return bitmap ^ (1 << position) } https://github.com/sirgallo/cmapv2/blob/main/utils.go#L41-L4... Calling it twice on the same index flips the bit back to 0. During branch-creation on insert and during delete, this function is invoked multiple times on
Read the rest
the same index, clearing a bit that should remain set and leaving orphaned children. --- Invalid assumptions re: interior pointers Only the root pointer is read with `atomic.LoadPointer`. All deeper fields like `children[pos]`, `bitmap`, and the byte-slice keys/values, are accessed directly after a successful CAS. Readers therefore race with writers that mutate these fields in place -- race condition, memory model violation, etc. pos := cMap.getPosition(node.Bitmap(), hash, level) if node.Child(pos).IsLeaf() && bytes.Equal(key, node.Child(pos).Key()) { return node.Child(pos).Value() } https://github.com/sirgallo/cmapv2/blob/main/operation.go#L5... --- All xxxRecursive functions rely on those invalid interior pointer assumptions Sequence in `putRecursive` / `deleteRecursive` is 1. `curr := atomic.LoadPointer(ptr)` 2. Build `nodeCopy` 3. Recurse; grandchildren are mutated in place 4. `atomic.CompareAndSwap(ptr, curr, nodeCopy)` https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1... If another goroutine has already swapped in a different copy of `curr` (and mutated it) the CAS still succeeds because the pointer value is unchanged, merging incompatible sub-tries and corrupting the data --- Use-after-free in sync.Pool On CAS failure the freshly built `nodeCopy` is immediately returned to a `sync.Pool` -- undefined behavior cMap.pool.PutNode(nodeCopy) // may race with outstanding readers https://github.com/sirgallo/cmapv2/blob/main/operation.go#L1... Other goroutines still holding references to that node can now access a reclaimed object, oops. --- K/V Aliasing Keys and values (both []byte slices, which are not safe for concurrent r/w access) are stored by reference, a mistake: n.setKey(key) n.setValue(value) If the caller mutates those slices later (or concurrently in another goroutine), data races ahoy --- Reader panics, etc. - `getRecursive` accesses `children[pos]` without bounds or nil checks, concurrent shrink can make `pos` invalid - `GetIndex` allows a negative `shiftSize` once `level >= 7` with `chunkSize = 5`, producing nonsense indices and potential slice-out-of-bounds
In Cmapv2: A high performance, concurrent map

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.