Skip to content

fix(geohash): publish currentGeohash writes to the threads that read it - #895

Open
Chessing234 wants to merge 1 commit into
permissionlesstech:mainfrom
Chessing234:geohash-repo-sync
Open

fix(geohash): publish currentGeohash writes to the threads that read it#895
Chessing234 wants to merge 1 commit into
permissionlesstech:mainfrom
Chessing234:geohash-repo-sync

Conversation

@Chessing234

Copy link
Copy Markdown

GeohashRepository synchronizes every accessor that touches its shared maps — eighteen of them — but currentGeohash is a plain var with two unsynchronized accessors:

private var currentGeohash: String? = null

fun setCurrentGeohash(geo: String?) { currentGeohash = geo }
fun getCurrentGeohash(): String? = currentGeohash

It is written from the UI thread when the user picks a channel (GeohashViewModel.selectLocationChannel, MainActivity) and read from Nostr handler and timer threads. Several of those reads are inside the @Synchronized methods — refreshGeohashPeople, updateParticipant, displayNameForNostrPubkey — and holding the lock on the read side buys nothing when the write side never takes it: there is no happens-before edge, so a stale value can persist indefinitely.

Two places that shows up:

  • startGeoParticipantsTimer loops while (repo.getCurrentGeohash() != null), so a missed write keeps refreshing participants for a channel the user has left;
  • displayNameForNostrPubkey uses it to derive the identity that decides whether a pubkey is us, so a stale geohash can label someone else's message with your nickname, or drop yours.

Synchronizing the two accessors matches the rest of the class. NotificationManager holds the same state and marks it @Volatile for this reason, so the codebase already treats it as cross-thread state.

./gradlew :app:testDebugUnitTest :app:lintDebug passes locally (rc=0). No behaviour test: a missing happens-before edge cannot be observed reliably from a unit test, and asserting it would only encode a timing accident.

GeohashRepository synchronizes every accessor that touches its shared
maps - eighteen of them - but currentGeohash is a plain var with two
unsynchronized accessors, and it is written from the UI thread when the
user picks a channel while Nostr handler and timer threads read it.

Several of those reads happen inside the @synchronized methods
(refreshGeohashPeople, updateParticipant, displayNameForNostrPubkey), and
holding the lock on the read side buys nothing when the write side never
takes it: there is no happens-before edge, so a stale value can persist.
Two ways that shows up: startGeoParticipantsTimer loops
`while (repo.getCurrentGeohash() != null)` and keeps refreshing a channel
the user has left, and displayNameForNostrPubkey derives the identity for
the wrong geohash when deciding whether a pubkey is us.

Synchronize the two accessors, matching the rest of the class.
NotificationManager keeps the same state @volatile for this reason.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant