-
Notifications
You must be signed in to change notification settings - Fork 580
refactor: CapsuleStore with staged writes #19449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e705402 to
e770876
Compare
nventuro
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some more comments, but it's already looking great! Address them and merge as you see fit. Thanks!
| * Deletes a capsule on the stage of a job. Note the capsule will still | ||
| * exist in storage until the job is committed. | ||
| */ | ||
| #deleteOnStage(jobId: string, dbSlotKey: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is is 'stage' or 'staged'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are staged capsules which mean they are on stage 🤡. Naming in this whole series of PR has not been my forte tbh. I re-think how I should call this.
| const dataBuffer = await this.#capsules.getAsync(dbSlotKey); | ||
| if (!dataBuffer) { | ||
| return null; | ||
| } | ||
|
|
||
| return dataBuffer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const dataBuffer = await this.#capsules.getAsync(dbSlotKey); | |
| if (!dataBuffer) { | |
| return null; | |
| } | |
| return dataBuffer; | |
| return await this.#capsules.getAsync(dbSlotKey) ?? null; |
| */ | ||
| async #getFromStage(jobId: string, dbSlotKey: string): Promise<Buffer | null | undefined> { | ||
| const jobStagedCapsules = this.#getJobStagedCapsules(jobId); | ||
| let staged: Buffer | null | undefined = jobStagedCapsules.get(dbSlotKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need explicit types here?
| if (staged === undefined) { | ||
| // If we don't have a staged version of this dbSlotKey, first we check if there's one in DB | ||
| staged = await this.#loadCapsuleFromDb(dbSlotKey); | ||
| } | ||
| return staged; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd do
| if (staged === undefined) { | |
| // If we don't have a staged version of this dbSlotKey, first we check if there's one in DB | |
| staged = await this.#loadCapsuleFromDb(dbSlotKey); | |
| } | |
| return staged; | |
| if (staged !== undefined) { | |
| return staged; | |
| } else { | |
| // If we don't have a staged version of this dbSlotKey, first we check if there's one in DB | |
| return this.#loadCapsuleFromDb(dbSlotKey); | |
| } |
but maybe that's just me. It feels weird to do staged = db when we don't actually make the db value become staged.
| async deleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> { | ||
| await this.#capsules.delete(dbSlotToKey(contractAddress, slot)); | ||
| deleteCapsule(contractAddress: AztecAddress, slot: Fr, jobId: string) { | ||
| // When we commit this, we will interpret null as a deletion, so we'll propagate the delete to the KV store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // When we commit this, we will interpret null as a deletion, so we'll propagate the delete to the KV store |
I don't think needs needs clarifying at the callsite
| * exist in storage until the job is committed. | ||
| */ | ||
| #deleteOnStage(jobId: string, dbSlotKey: string) { | ||
| this.#getJobStagedCapsules(jobId).set(dbSlotKey, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.#getJobStagedCapsules(jobId).set(dbSlotKey, null); | |
| // A staged null value indicates deletion, and will result in the KV store entry being deleted on commit | |
| this.#getJobStagedCapsules(jobId).set(dbSlotKey, null); |
| // This transactional context gives us "copy atomicity": | ||
| // there shouldn't be concurrent writes to what's being copied here. | ||
| // Equally important: this in practice is expected to perform thousands of DB operations | ||
| // and not using a transaction here would heavily impact performance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use the full 120 line length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there are places where it hurts my eyes to introduce a line break. Is this a case of conflicting OCD's? :P
|
Thanks for the review! I'll merge as is and address comments on the next one in line, so I don't miss the integration train any longer |
Second part of the series started with #19445. This makes the CapsuleStore work based on staged writes. With this, capsules aren't written to persistent storage until PXE decides to commit the job.
1de3908 to
b30c796
Compare
Flakey Tests🤖 says: This CI run detected 2 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
Second part of the series started with #19445.
This makes the CapsuleStore work based on staged writes. With this, capsules aren't written to persistent storage until PXE decides to commit the job.