Skip to content

Conversation

jmpesp
Copy link
Contributor

@jmpesp jmpesp commented Mar 30, 2022

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.

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.
@jmpesp jmpesp requested a review from zephraph March 30, 2022 16:20
/* Disk configuration */
size_bytes INT NOT NULL,
origin_snapshot UUID
block_size INT NOT NULL,
Copy link
Contributor

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_sizes or is it unconstrained?

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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?

Copy link
Collaborator

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.

Copy link
Contributor Author

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

Copy link
Contributor

@zephraph zephraph left a 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.

@jmpesp
Copy link
Contributor Author

jmpesp commented Apr 7, 2022

after c5d7620, this is now ready for a final review

Comment on lines 368 to 373
CREATE TYPE omicron.public.block_size AS ENUM (
'traditional',
'iso',
'advancedformat'
);

Copy link
Contributor

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?

Suggested change
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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, done in d5db0b5

Comment on lines 5369 to 5376
"block_size": {
"description": "size of blocks for this Disk. valid values are: 512, 2048, or 4096",
"allOf": [
{
"$ref": "#/components/schemas/ByteCount"
}
]
},
Copy link
Contributor

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.

Copy link
Contributor Author

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

@jmpesp jmpesp merged commit 2515940 into oxidecomputer:main Apr 8, 2022
@jmpesp jmpesp deleted the block_size_either_512_or_4096 branch April 8, 2022 20:09
leftwo pushed a commit that referenced this pull request Jan 27, 2025
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)
leftwo added a commit that referenced this pull request Jan 27, 2025
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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants