Repository navigation
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 5 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7dbb16c. Configure here.
|
|
||
| // Decrement counter when done | ||
| active_tasks.fetch_sub(1, Ordering::SeqCst); | ||
| }); |
There was a problem hiding this comment.
Unordered tasks lose object updates
High Severity
write, update, and delete each tokio::spawn an independent task with no per-object ordering. A later update or delete can commit before the matching write, so expirations are skipped and deleted objects can be reinserted.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 7dbb16c. Configure here.
There was a problem hiding this comment.
we were actually talking about something related to this today. i don't think we can guarantee today that, if two requests are racing, the storage backend and the change stream will resolve the race in the same way. i signed off on that for COGS because it's not really a big issue there, but it is more meaningful for this GC use case
i don't have a great answer for what to do about that right now. just surfacing it here, i guess
There was a problem hiding this comment.
I remember I talked about this with Jan and Lorenzo, AFAIK we didn't came up to a conclusion yet.
| #[cfg(feature = "storage-cogs")] | ||
| mod cost_tracker; | ||
| mod factory; | ||
| mod garbage_collector_sqlite; |
There was a problem hiding this comment.
Collector is never constructed
Medium Severity
SqliteGarbageCollectorStream lives in a private module and is never re-exported or built by ChangeStreamFactory. No backend can select this collector, so the new feature is unreachable.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7dbb16c. Configure here.
It's so hard to develop this on Windows. I need to grab my Linux laptop.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #653 +/- ##
==========================================
+ Coverage 91.27% 91.36% +0.08%
==========================================
Files 116 117 +1
Lines 23496 24028 +532
==========================================
+ Hits 21445 21952 +507
- Misses 2051 2076 +25
☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
matt-codecov
left a comment
There was a problem hiding this comment.
a couple questions:
- do we have performance goals for self-hosted deployments? i have been burned by poor single-insert sqlite performance before. if we need high throughput, we may want to introduce batched queries, but it introduces some risk of inventory corruption if we crash without flushing batches
- do we have scaling requirements for self-hosted deployments? i've seen a few different "distributed sqlite" projects (https://rqlite.io/ / https://docs.fly.io/litefs/how-it-works/) but generally consider sqlite to be node-local
|
|
||
| // Decrement counter when done | ||
| active_tasks.fetch_sub(1, Ordering::SeqCst); | ||
| }); |
There was a problem hiding this comment.
we were actually talking about something related to this today. i don't think we can guarantee today that, if two requests are racing, the storage backend and the change stream will resolve the race in the same way. i signed off on that for COGS because it's not really a big issue there, but it is more meaningful for this GC use case
i don't have a great answer for what to do about that right now. just surfacing it here, i guess
If they're using k8s (the unofficial helm chart), they want to use the postgres implementation of this garbage collector. In which I will implement after SQLite is correctly implemented. This is how Taskbroker is doing as well, they provide both options, with SQLite as default.
I've contributed to rqlite before, but no thanks, let's not consider that approach. |
There was a problem hiding this comment.
The biggest point to resolve will be #653 (comment) but in the meantime we can get the rest of the things in order before we find a solution for that.
matt-codecov
left a comment
There was a problem hiding this comment.
#677 changed the ChangeStream trait to help write GC correctly. unfortunately you will need to rebase and tweak your PR to implement:
begin_write(): create the GC record before committing in the storage backendbegin_update(): lengthen the expiration in GC before committing in the storage backendcommit_delete(): delete the GC record after deleting the stored object
if begin_write() or begin_update() fail, it's not safe to allow the backend commit to happen. otherwise we can permanently leak objects or cause GC to delete them prematurely. so those functions have to .await rather than spawn and they have to surface failure to the caller
if commit_delete() fails it's kind of harmless. GC will just have a ghost record floating around until its expiry. if the ghost record has manual expiration then it'll float around forever, but that's... probably a small edge case.


Introduces
SqliteGarbageCollectorandSqliteGarbageCollectorStreamwhich implementsChangeStream.This is required for filesystem & S3-compatible API backends.
Note that it's not wired to the backends yet.
Supersedes #582
Refs FS-482