Skip to content

RDM/DVLS migration requests: locking, SQL and facade compatibility, legacy codecs - #80

Merged
Marc-André Moreau (mamoreau-devolutions) merged 1 commit into
masterfrom
claude/ahtola-requests-3fb462
Oct 7, 2026
Merged

Marc-André Moreau (mamoreau-devolutions) merged 1 commit into
masterfrom
claude/ahtola-requests-3fb462

Conversation

@mamoreau-devolutions

Copy link
Copy Markdown
Contributor

Implements the 36 fixes and improvements that Remote Desktop Manager and Devolutions Server asked for when moving to Ahtola v0.10.0. 32 are done; #13, #28, #32 and #34 are partial or handled differently (see below).

Locking and concurrency (#1–#6)

SQL compatibility (#7–#11, #17)

  • PRAGMA auto_vacuum does nothing once tables exist.
  • CURRENT_TIMESTAMP is accepted in upserts.
  • CTE collation precedence matches SQLite.
  • VACUUM INTO doesn't take the write lock.
  • locking_mode=EXCLUSIVE takes its lock on the next statement.
  • ALTER TABLE ADD COLUMN inserts the new column before the table constraints.

Files and journal modes (#12–#16, #18)

  • A read-only open with -wal but no -shm falls back to foreign read-only mode.
  • When the last connection closes, an empty -wal and the -shm are removed, as native SQLite does. A WAL that still holds frames, or one next to replica artifacts, is kept.
  • An existing 0-byte file opens as a new database, unless a -wal or -journal exists next to it.
  • busy_timeout, wal_autocheckpoint and journal_size_limit are honoured.
  • WAL stays the default journal mode. A Journal Mode keyword creates a database in DELETE mode.

ADO.NET facade (#19–#27)

  • GUIDs: BinaryGUID=False binds GUIDs as text; DbType.Guid with a string value is parsed.
  • Type mapping: new Type Mapping=SystemDataSQLite option. The *ID column-name heuristic is now opt-in. GetValue returns non-GUID content in a guid column as stored.
  • Connection strings: System.Data.SQLite keywords plus Ignore Unknown Keywords. Commands auto-enlist in the connection's transaction when Auto Enlist Transaction is set (off by default).
  • Errors: a wrong key raises error 26 with SQLite's "file is encrypted or is not a database" text.
  • Defaults: LocalProvider reports Managed when the keyword is absent. BLOB columns still report object by default (fix: treat omitted proto3 scalars in a logical-log range as zero #23), because DVLS stores text in BLOB columns.

Page codecs (#28–#31)

  • Legacy codecs: Ahtola.Data.Sqlite.Codecs adds the System.Data.SQLite RC4 and wxSQLite3 AES-128 codecs, plus LegacyPageCodecs.Detect/DetectFile. Both are validated against files written by the native engines. SQLCipher v4 and ChaCha20 are not included: no native-written fixtures were available.
  • Connection API: PageCodecCandidates and SelectedPageCodec. IPageCodec.MatchesHeader and PageCodecKeyMismatchException let a codec report a wrong key separately from a corrupt file.
  • ChangePageCodec(IPageCodec?): re-encrypts the file in place under an exclusive lock.
  • Docs: CodecId, threading and ownership.

Performance (#32, #33)

  • Hot spots removed: the internally caught exceptions on the schema-ladder path (738 per run, down to 2) and slow schema-page rebuilding.
  • Remaining gap: file-backed ladders still run at about 1.5–2× native. The remaining cost is spread across a checkpoint after each DDL commit, catalog copying and reparsing.
  • Benchmarks: new RdmDvlsWorkloadBenchmarks compares Ahtola with Microsoft.Data.Sqlite + e_sqlite3. It covers the ladder, bulk insert, large text, LIKE scans and open, with each codec.
    • It flagged high allocation on bulk inserts of 20 KB text, which needs follow-up.

Packaging and docs (#34–#36)

  • EF Core pins move to 10.0.12 / 9.0.20. The Microsoft.Data.Sqlite.Core dependency stays because EF Core's SQLite provider needs it.
  • New docs/migrating-from-sqlite-providers.md. dotnet-packages.md, the README and the WAL interoperability contract are updated.

Also fixed

A second connection got "no such table" for a table another connection had just created. This bug predates this branch.

Tests

  • New tests: RdmDvlsCompatibilityTests (42) and LegacyPageCodecTests (13, with fixtures from RDM).
  • Updated tests: existing tests that expected the old behaviour (WAL left on disk after close, exception types, the GUID heuristic).
  • Full suite (net10.0): 8,414 tests passed. It ran from a copy of the build output in a temp folder. The failures there were long paths that native SQLite can't open, plus tests that need the repo checkout. All of them pass when rerun from the repo, after the test updates above.
  • Checks: validate-trim passes with 0 Ahtola warnings. validate-project-closure and the package-closure script tests (16/16) pass.
  • Formatting: the changed files add no new format-check violations. Violations that predate this branch remain.

🤖 Generated with Claude Code

…ility, legacy codecs

Locking: BEGIN IMMEDIATE and a deferred transaction's first write hold a
cross-process writer reservation until the transaction ends; detect peer
WAL commits by content token; honour busy timeout for cross-process waits
(polite RESERVED wait in rollback-journal mode); surface lock errors as
SqliteException SQLITE_BUSY; retryable busy commits.

SQL/files: auto_vacuum no-op once tables exist, CURRENT_TIMESTAMP in upsert,
CTE collation precedence, VACUUM INTO without the write lock, lazy
locking_mode=EXCLUSIVE, ALTER TABLE ADD COLUMN text placement, read-only
open without -shm, idle -wal/-shm cleanup on last close, 0-byte file open,
busy_timeout/wal_autocheckpoint/journal_size_limit pragmas.

Facade: text GUID binding, DbType.Guid strings, System.Data.SQLite
keywords and type mapping, opt-in *ID heuristic, auto-enlist, wrong-key
SQLite error text, LocalProvider reports Managed.

Codecs: System.Data.SQLite RC4 and wxSQLite3 AES-128 codecs with
detection, PageCodecCandidates, MatchesHeader, PageCodecKeyMismatchException,
ChangePageCodec. Also fixes stale catalog visibility for DDL made by
another connection, schema leaf packing hot spots, RDM/DVLS workload
benchmarks, EF Core 10.0.12 / 9.0.20 pins and migration docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mamoreau-devolutions
Marc-André Moreau (mamoreau-devolutions) merged commit 9651dab into master Oct 7, 2026
11 checks passed
@mamoreau-devolutions
Marc-André Moreau (mamoreau-devolutions) deleted the claude/ahtola-requests-3fb462 branch October 7, 2026 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant