Skip to content

Concurrent registrations into NpgsqlTypeMapper.Mappings are silently lost #406

Description

@jeremydmiller

Split out of #398 / #402.

NpgsqlTypeMapper.Mappings is the documented extension point for consuming code to register custom Npgsql mappings:

This is lazily calculated instead of precached because it allows consuming code to register custom npgsql mappings prior to execution.

Reads are safe. JasperFx.Core.Cache is backed by an ImHashMap, so an enumerating reader sees an immutable snapshot — it cannot tear or throw Collection was modified. (This corrects the reader-side race I speculated about in #402; a 4.3M-read stress run against concurrent writers produced zero failures.)

Writes are not. The indexer setter is a non-atomic read-modify-write over the ImHashMap, so concurrent writers clobber each other:

8 threads x 5,000 distinct keys
expected 40,000 new entries, observed 7,660  ->  LOST 32,340  (81%)

Practical severity is low: registrations normally happen once at startup on one thread. But it is silent — a lost registration surfaces much later as a wrong or missing type mapping, with nothing pointing back here.

The setter belongs to JasperFx.Core.Cache, so Weasel cannot fix it directly. Options:

  • Document that Mappings must be populated before concurrent use (cheapest).
  • Have Weasel funnel writes through its own guarded API rather than exposing the Cache field.
  • Raise the lost-update behaviour upstream in JasperFx.Core.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions