Skip to content

Two concurrent runs (e.g. two Scans, or Import during a Scan) silently overwrite each other's descriptions in persistent_state.json #164

Description

@matt-edmondson

What's wrong

Program.cs:24 loads the whole store into memory once, when the process starts. Every later save writes that process's entire in-memory copy back to disk:

  • Verbs/Scan.cs:141-142 saves after each image.
  • Scan.cs:106 and Import.cs:65 save as well.

The lock at Scan.cs:137 only serializes threads inside one process. Nothing locks the file across processes, and nothing re-reads and merges the file before writing. So whichever process saves last wins, and the other process's additions are thrown away.

Failure scenario

Two Scan runs started together on different folders (A and B, 3 images each), sharing one store:

  • Actual: both print "Scan complete. Total descriptions in database: 3". Afterwards Stats shows 3 descriptions, and persistent_state.json contains only folder A's paths. B's 3 descriptions are lost with no message, along with the model time spent generating them.
  • Expected: 6 descriptions, or at least a refusal to start the second run.

The same thing silently undoes an Import or a Configure change made while a Scan is running: the Scan's next per-image save writes back its stale copy.

I reproduced this with two real processes against a stub Ollama server that delays each response by 0.7 s. Long, model-bound scans make the overlap window large in real use.

Suggested fix

Either of these would do:

  1. Take an exclusive lock (e.g. a lock file opened with FileShare.None) for the whole run of any verb that writes to the store. A second run should fail fast with a clear message.
  2. Under a short cross-process lock, re-load the file and merge into it before every save: take the union of Descriptions by hash and of KnownPaths.

Option 1 is simpler. Option 2 lets parallel scans of different folders work.

Acceptance criteria

  • Two concurrent Scans over separate folders either both end up in the store (union), or the second one refuses to run with a clear message. No description is silently lost.
  • An Import or Configure made during a Scan is not reverted by the Scan's later saves.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreadyFully specified; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions