Skip to content

Fix #25010 – Deleted favorites reappear after app restart#25262

Closed
nazar-kutz wants to merge 11 commits into
masterfrom
fix-25010-deleted-favorites-reappear
Closed

Fix #25010 – Deleted favorites reappear after app restart#25262
nazar-kutz wants to merge 11 commits into
masterfrom
fix-25010-deleted-favorites-reappear

Conversation

@nazar-kutz

Copy link
Copy Markdown
Contributor

Problem

Deleting a favorite point and immediately closing the app caused
the point to reappear after restart. This happened because deletion
was applied to in-memory state immediately, but the actual GPX file
save was performed asynchronously. If the process was killed before
the async task completed, the GPX files still contained the deleted
points. On next launch, loadFavorites() would merge them back from
the external files.

The issue was especially noticeable with large favorites collections
(10,000+ points) where the save task could take 30+ seconds.

Root cause

saveCurrentPointsIntoFile(true) queues an AsyncTask on a
singleThreadExecutor. Android can kill the process before this task
completes, leaving GPX files in the old state.

Fix

Introduced a tombstone mechanism via PendingFavoriteDeletions —
a lightweight append-only file (favorites_deletions.tmp) that is
written synchronously at the moment of deletion, before the async
save is queued.

On the next loadFavorites() call, pending deletions are applied
to both internal and external group maps before merge, ensuring
deleted points and groups are filtered out regardless of whether
the previous async save completed.

The tombstone file is cleared inside SaveFavoritesTask.saveAllGroups()
only after all GPX writes succeed, so if a save fails mid-way the
tombstone is preserved for the next launch.

Changes

  • PendingFavoriteDeletions.kt — new class, stores sets of deleted
    point keys and group names, handles serialization
  • FavouritesFileHelper.java — added tombstone file read/write/clear
  • FavouritesHelper.java — apply pending deletions in loadFavorites(),
    write tombstone in delete() and deleteFavourite()
  • SaveFavoritesTask.java — clear tombstone after successful save
  • IndexConstants.kt — added TMP_FILE_EXT constant

Testing

Reproduced on OsmAnd+ 5.3.8 / 5.4.0 with 23,000+ favorites.
Verified fix by deleting a favorite and force-stopping the app
immediately — point no longer reappears after restart.

@nazar-kutz nazar-kutz linked an issue Jun 14, 2026 that may be closed by this pull request
@Chumva

Chumva commented Jun 19, 2026

Copy link
Copy Markdown
Member

The tombstone journal is a reasonable short-term mitigation for deletes, but it does not address the root problem: every favourite edit still triggers a full GPX read/merge/rewrite/backup pipeline, so persistence remains slow and killable. It also only protects deletes, while adds/edits can still be lost before the async save completes.

nazar-kutz and others added 7 commits June 22, 2026 22:53
This patch introduces a coalescing mechanism for rapid favorite save requests. By wrapping parameters in `SaveFavoritesParams`, newer save requests now safely merge with and cancel pending tasks, preventing unnecessary disk I/O queueing.

Key improvements:
- Added `taskLock` in `FavouritesFileHelper` for thread-safe task merging and cancellation.
- Fixed `ConcurrentModificationException` during group iteration.
- Added `isCancelled()` checks to abort superseded tasks early.
- Guaranteed data integrity by properly merging groups and accumulating listeners.
- Replaced individual file write operations with a single batch write mechanism (`savePendingDeletions`) when deleting multiple favorite points or groups.
- Improved disk performance by accumulating serialized deletion entries in memory and writing them to the temporary file in a single `BufferedWriter` transaction.
- Updated `FavouritesHelper` to pass collections directly instead of iterating and triggering separate I/O calls for each deleted item.
- delete redundant code
- restore significant comments
- Replace internal file diffing with tombstone to detect deleted points
- Write external files first as source of truth, internal snapshot after
- Clear tombstone only after the last queued task completes
- Rename pendingSaveTask to runningSaveTask
# Conflicts:
#	OsmAnd/src/net/osmand/plus/myplaces/favorites/FavouritesFileHelper.java
#	OsmAnd/src/net/osmand/plus/myplaces/favorites/FavouritesHelper.java
#	OsmAnd/src/net/osmand/plus/myplaces/favorites/SaveFavoritesTask.java
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.

Deleting "favorites" from map quickly causes them to reappear

2 participants