Implementation Analysis of Go's sync.Map for Concurrent Access

Core Data Structures

Entry Structure

type slot struct {
    valuePointer atomic.Pointer[interface{}]
}

The slot struct represents a key-value storage location within the concurrent map. It uses an atomic pointer to ensure thread-safe access to stored values without requiring external synchronization.

Read-Only View

type snapshot struct {
    data      map[interface{}]*slot
    outdated  bool
}

This structure maintains a read-only copy of map data for fast concurrent reads. The outdated flag indicates when the primary storage contains keys missing from this snapshot.

Concurrent Map

type ConcurrentMap struct {
    lock    sync.Mutex
    snapshot atomic.Pointer[snapshot]
    primary map[interface{}]*slot
    cacheMisses int
}

The main structure employs dual storage: a lock-free snapshot for reads and a locked primary map for writes. This design optimizes for frequent read operations while maintaining write consistency.

Key Operations

Retrieving Values

func (cm *ConcurrentMap) Get(key interface{}) (value interface{}, found bool) {
    snap := cm.getSnapshot()
    s, exists := snap.data[key]
    if !exists && snap.outdated {
        cm.lock.Lock()
        snap = cm.getSnapshot()
        s, exists = snap.data[key]
        if !exists && snap.outdated {
            s, exists = cm.primary[key]
            cm.recordMiss()
        }
        cm.lock.Unlock()
    }
    if !exists {
        return nil, false
    }
    return s.loadValue()
}

Value retrieval first checks the snapshot without locking. If the key isn't found and the snapshot is outdated, it acquires the lock and searches the primary map.

Storing Values

func (cm *ConcurrentMap) Put(key, val interface{}) (previous interface{}, existed bool) {
    snap := cm.getSnapshot()
    if s, ok := snap.data[key]; ok {
        if oldVal, swapped := s.attemptSwap(&val); swapped {
            if oldVal == nil {
                return nil, false
            }
            return *oldVal, true
        }
    }

    cm.lock.Lock()
    snap = cm.getSnapshot()
    if s, ok := snap.data[key]; ok {
        if s.reactivate() {
            cm.primary[key] = s
        }
        if oldVal := s.swapValue(&val); oldVal != nil {
            existed = true
            previous = *oldVal
        }
    } else if s, ok := cm.primary[key]; ok {
        if oldVal := s.swapValue(&val); oldVal != nil {
            existed = true
            previous = *oldVal
        }
    } else {
        if !snap.outdated {
            cm.initializePrimary()
            cm.snapshot.Store(&snapshot{data: snap.data, outdated: true})
        }
        cm.primary[key] = newSlot(val)
    }
    cm.lock.Unlock()
    return previous, existed
}

Value storage attempts lock-free updates via the snapshot first. When necessary, it acquires the lock to update the primary storage and manages state transitions between snapshot and primary maps.

State Management

Entry States

Antries can exist in three states:

  • Active: Contains a valid value pointer
  • Cleared: Pointer is nil, indicating deletion
  • Removed: Special marker indicating permanent removal from primary storage

State Transition Example

func (s *slot) attemptSwap(newVal *interface{}) (*interface{}, bool) {
    for {
        current := s.valuePointer.Load()
        if current == removedMarker {
            return nil, false
        }
        if s.valuePointer.CompareAndSwap(current, newVal) {
            return current, true
        }
    }
}

This method demonstratse how atomic operations prevent updates to permanently removed entries while allowing updates to temporarily cleared ones.

Performance Characteristics

This implementation excels in read-heavy workloads with infrequent writes. For scenarios involving frequent key updates, performance may approach that of a standard map protected by a mutex due to increased lock contention.

The distinction between cleared and removed states is critical for maintaining consistency between snapshot and primary storage during map reorganization.

Tags: Go Concurrency Data Structures sync.Map Atomic Operations

Posted on Thu, 05 Nov 2026 16:24:18 +0000 by vasse