-
Notifications
You must be signed in to change notification settings - Fork 54
Block size must be given during disk create #834
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
Block size must be given during disk create #834
Conversation
Block size of disks must be variable and declared during disk creation. In other instances, it can be inherited (for example, creating a disk from a snapshot will set the block size to whatever the snapshot's was). Store this in the disks table. Also, prepare for creating disks from images and snapshots by adding the appropriate columns to the disks table. Externally, the API should be returning names, not IDs, but this commit doesn't tackle that. At minimum this will require Nexus to convert a db::model::Disk into an external::Disk by looking up ids and filling in the appropriate names (instead of a simple From impl). I'll create an issue to track this work.
common/src/sql/dbinit.sql
Outdated
/* Disk configuration */ | ||
size_bytes INT NOT NULL, | ||
origin_snapshot UUID | ||
block_size INT NOT 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.
Are there only two valid block_size
s or is it unconstrained?
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.
It's an interesting question here about what we want to store in the database. In general today we only have block sizes like 512 and 4096; however, there could be others that we want to logically advertise especially as SSDs continue to increase their internal block size or we want to give VMs more flexibility here. While an integer is the simplest, maybe it's worth considering a semantic enum or otherwise figuring out how we ensure that invalid and unsupported values don't make it in. I'm not sure what our general db strategy is in that respect.
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'm also not sure what our general db strategy is here.
CRDB supports constraints, something like:
block_size INT NOT NULL CONSTRAINT block_size CHECK (block_size = 512 OR block_size = 4096),
Enums are more Rust work but possible too.
These check constraints can be changed using ALTER TABLE in the future if we plan on supporting more block sizes. If we only ever add supported block sizes, then that means adding another OR block_size = X
clause:
root@:26257/omicron> alter table disk drop constraint block_size;
ALTER TABLE
Time: 91ms total (execution 91ms / network 0ms)
root@:26257/omicron> alter table disk add constraint block_size check (block_size = 512 OR block_size = 4096 OR block_size = 2048);
ALTER TABLE
Time: 102ms total (execution 101ms / network 0ms)
Rolling back that schema change is problematic because rows could have made it in with block size X, however the documentation mentions that:
The CHECK constraint specifies that values for the column in INSERT or UPDATE statements must return TRUE or NULL for a Boolean expression.
so at least SELECTs will still work.
There would also have to be an additional change to Crucible to support any new block sizes.
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.
cc @davepacheco do you have thoughts?
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.
My inclination would be to use an enum. We've done that in a bunch of places. I don't think we use check
much today. check
may well be just as good but on the surface it seems like an enum (with a corresponding Rust enum) would ensure only valid values could be represented in Rust as well as in SQL, while with check
I think you could still easily construct invalid Rust representations.
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.
Added an enum in a20f0eb
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.
Overall, looks good. None of my feedback/questions are blocking.
actually commit tests
after c5d7620, this is now ready for a final review |
CREATE TYPE omicron.public.block_size AS ENUM ( | ||
'traditional', | ||
'iso', | ||
'advancedformat' | ||
); | ||
|
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.
[not blocking]
Instead of carrying over these labels could we just do the byte value of the sizes in string form?
CREATE TYPE omicron.public.block_size AS ENUM ( | |
'traditional', | |
'iso', | |
'advancedformat' | |
); | |
CREATE TYPE omicron.public.block_size AS ENUM ( | |
'512', | |
'2048', | |
'4096' | |
); |
The labels as are don't seem to have as much meaning in context.
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.
nice, done in d5db0b5
"block_size": { | ||
"description": "size of blocks for this Disk. valid values are: 512, 2048, or 4096", | ||
"allOf": [ | ||
{ | ||
"$ref": "#/components/schemas/ByteCount" | ||
} | ||
] | ||
}, |
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 think it'd be nice if we had a BlockSize
entry in the schema that look something like this:
{
"BlockSize": {
"description": "Valid block sizes for a disk",
"type": "integer",
"enum": [
512,
2048,
4096
]
}
}
It's not something we need to do in this PR, but it'd be nice to work towards. This would generate better types for us on the client and make it easier to automatically infer client side validation. As-is now we'd have to add special handling on the client for validation which is fine for where we are now but less desirable long term.
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.
No better time than the present :) done in ce7e8fd
Crucible changes are: Allow read only activation with less than three downstairs (#1608) Tweaks to automatic flush (#1613) Update Rust crate twox-hash to v2 (#1547) Remove `LastFlushAck` (#1603) Correctly print 'connecting' state (#1612) Make live-repair part of invariants checks (#1610) Simplify mend region selection (#1606) Generic read test for crutest (#1609) Always remove skipped jobs from dependencies (#1604) Add libsqlite3-dev install step to Github Actions CI (#1607) Move Nexus notification to standalone task (#1584) DTrace cleanup. (#1602) Reset completed work Downstairs on a `Barrier` operation (#1601) Upstairs state machine refactoring (3/3) (#1577) Propolis changes are: Wire up initial support for AMD perf counters build: upgrade tokio to 1.40.0 (#836) build: explicitly install libsqlite3-dev in CI (#834) add JSON output format to cpuid-gen (#832)
Crucible changes are: Allow read only activation with less than three downstairs (#1608) Tweaks to automatic flush (#1613) Update Rust crate twox-hash to v2 (#1547) Remove `LastFlushAck` (#1603) Correctly print 'connecting' state (#1612) Make live-repair part of invariants checks (#1610) Simplify mend region selection (#1606) Generic read test for crutest (#1609) Always remove skipped jobs from dependencies (#1604) Add libsqlite3-dev install step to Github Actions CI (#1607) Move Nexus notification to standalone task (#1584) DTrace cleanup. (#1602) Reset completed work Downstairs on a `Barrier` operation (#1601) Upstairs state machine refactoring (3/3) (#1577) Propolis changes are: Wire up initial support for AMD perf counters build: upgrade tokio to 1.40.0 (#836) build: explicitly install libsqlite3-dev in CI (#834) add JSON output format to cpuid-gen (#832) --------- Co-authored-by: Alan Hanson <[email protected]>
Block size of disks must be variable and declared during disk creation.
In other instances, it can be inherited (for example, creating a disk
from a snapshot will set the block size to whatever the snapshot's was).
Store this in the disks table.
Also, prepare for creating disks from images and snapshots by adding
the appropriate columns to the disks table.
Externally, the API should be returning names, not IDs, but this commit
doesn't tackle that. At minimum this will require Nexus to convert a
db::model::Disk into an external::Disk by looking up ids and filling in
the appropriate names (instead of a simple From impl). I'll create an
issue to track this work.