serverpod-offline-sync/test/serverpod_offline_sync_test_server
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Tizian 「ティツィアーン」 b5450353b9
perf: Skip the projection pass after a local delete that cannot change it
insteadOfDelete ran the full foreign key projection after every local
delete. Its closure follows edges both ways, so it loads every row
connected to the deleted one, which in a schema whose tables all hang off
one another is nearly the whole database: one deleted row of a person's
8,000 flashcards loaded 56,000 of 56,350 CRDT rows and took about 8 s on
the calling isolate, most of it deserialising rows. Inserts and updates
have had a proof that the pass is unnecessary
(canLeaveLocalProjectionUnchanged); deletes had none.

canSkipProjectionAfterLocalDelete proves it for a delete: every table
the delete can cascade into is reached by cascade edges on id only, none
of them restricts its parent (a deleted child can release a parent
delete held back by it), none has a unique index (a released claim can
bring a contestant back) or lies in a component with a SET DEFAULT edge,
and no attempted value is pending in the connected tables. The delete's
own cascade (applyDeleteActions) then is the whole projection; otherwise
the full pass runs as before. applyDeleteActions also asks for the
visible children of a whole batch of parents at once for cascades by id,
instead of one query per parent.

On that database a single delete now takes 6-63 ms, a card with its
revisions, tags and reviews 46-145 ms instead of 28-39 s. The new tests
cover a restrict child deleted locally releasing a merged parent delete
(on the person tables, and on the chain tables, where the shortcut is
asked and declines: the test fails with the restrict condition removed)
and a cascade child deleted locally through the shortcut, its parent
then deleted by a merged remote delete. The core, server, integration
and simulation suites pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:38:40 +02:00
..
.test_databases test: Add a DST and tests reproducing found failures (#110) 2026-09-04 13:09:20 -03:00
bin refactor: Replace drift by serverpod as core engine (#33) 2026-05-03 09:09:23 -03:00
config fix: Preserve shared model and SQLite value types during sync (#118) 2026-09-16 00:07:51 -03:00
lib fix: Author the column default an upsert writes for a null foreign key (#164) 2026-10-08 22:48:47 -03:00
migrations fix: Author the column default an upsert writes for a null foreign key (#164) 2026-10-08 22:48:47 -03:00
test perf: Skip the projection pass after a local delete that cannot change it 2026-10-17 14:38:40 +02:00
.gitignore refactor: Move the core implementation to the shared package with no manual queries (#107) 2026-08-04 11:04:04 -03:00
analysis_options.yaml feat: Implement the sync protocol (#54) 2026-05-29 01:54:23 -03:00
CHANGELOG.md refactor: Replace drift by serverpod as core engine (#33) 2026-05-03 09:09:23 -03:00
dart_test.yaml test: Harden DST authored-state checks and workloads (#123) 2026-09-17 10:39:07 -03:00
pubspec.yaml fix: Prevent web deadlocks in transactional membership reads (#161) 2026-10-08 19:00:44 -03:00
README.md refactor: Replace drift by serverpod as core engine (#33) 2026-05-03 09:09:23 -03:00

serverpod_offline_sync_test_server

This is the starting point for your Serverpod server.

To run your server, you first need to start Postgres and Redis. It's easiest to do with Docker.

docker compose up --build --detach

Then you can start the Serverpod server.

dart bin/main.dart

When you are finished, you can shut down Serverpod with Ctrl-C, then stop Postgres and Redis.

docker compose stop