Skip to content
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

BUGFIX: full table scan preventing looking up bgp configs by name #6477

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

internet-diglett
Copy link
Contributor

Related

resolves #6471

@david-crespo
Copy link
Contributor

Why didn’t a test hit this? Not enough rows in the table to trigger it?

@bnaecker
Copy link
Collaborator

@david-crespo The size of the table doesn't matter, but I think you need to run a query looking for a record by name. Any tests we have must be looking up by primary key.

@bnaecker
Copy link
Collaborator

But speaking of, @internet-diglett it might be worth writing a regression test in this PR.

@internet-diglett
Copy link
Contributor Author

@bnaecker yeah, I was looking into beefing up our tests across the board for networking APIs, but some of that work also overlaps with another PR I'm working on so I don't know which I'm going to put it in at the moment 😂

@elaine-oxide
Copy link
Contributor

Please check if this will also fix #6619

Thank you!

@rcgoodfellow
Copy link
Contributor

I don't think this PR will fix 6619. The error in that issue is

DatabaseError(Unknown, "query `SELECT COUNT(*) FROM \\"bgp_config\\" WHERE (\\"bgp_config\\".\\"bgp_announce_set_id\\" = $1)` contains a full table/index scan which is explicitly disallowed")

but this PR is adding an index on the bgp_config name column, not the bgp_announce_set_id column.

@rcgoodfellow
Copy link
Contributor

We weren't missing an index for looking up BGP configs by name, what we were missing was the time_deleted NOT NULL filter on queries looking BGP configs up by name. There were some other indexes we were missing though, those have now been added.

I added a test that covers the API calls used in #6471 and #6619. Both of those issues are now addressed by this PR.

The test I wrote also surfaced the fact that the diesel count method was being used incorrectly in a few places that has now been fixed.

Copy link
Contributor

@elaine-oxide elaine-oxide left a comment

Choose a reason for hiding this comment

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

See comments. Reviewed for consistency.

nexus/db-model/src/schema_versions.rs Show resolved Hide resolved
Comment on lines 1007 to 1008
async fn test_delete_bgp_config_delete_by_name() {
let logctx = dev::test_setup_log("test_delete_bgp_config_by_name");
Copy link
Contributor

Choose a reason for hiding this comment

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

Should rename for clarity, since this deletes both bgp config and announce set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done

CREATE INDEX IF NOT EXISTS lookup_bgp_config_by_bgp_announce_set_id ON omicron.public.bgp_config (
bgp_announce_set_id
) WHERE
time_deleted IS NULL;
Copy link
Contributor

Choose a reason for hiding this comment

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

Double check if needed for line 2802

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes this is an index on a different field that is not already in the primary key so both the index and time deleted constraint are needed.

CREATE INDEX IF NOT EXISTS lookup_bgp_config_by_bgp_announce_set_id ON omicron.public.bgp_config (
bgp_announce_set_id
) WHERE
time_deleted IS NULL;
Copy link
Contributor

Choose a reason for hiding this comment

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

Double check if this is needed for schema/crdb/lookup-bgp-config-indexes/up02.sql

Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above, yes this is needed.

.count()
.execute_async(&conn)
.get_result_async(&conn)
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need to select all the rows if you just want to check whether there are any. Something like this should do it:

let configs_exist = diesel::dsl::select(diesel::dsl::exists(
  sps_bgp_peer_config_dsl::switch_port_settings_bgp_peer_config
    .filter(sps_bgp_peer_config::bgp_config_id.eq(id))
))
.get_result_async::<bool>(&conn)
.await?;

Compare:

let has_children = diesel::dsl::select(diesel::dsl::exists(
external_ip::table
.filter(external_ip::dsl::ip_pool_id.eq(pool_id))
.filter(external_ip::dsl::ip_pool_range_id.eq(range_id))
.filter(external_ip::dsl::time_deleted.is_null()),
))
.get_result_async::<bool>(&*conn)

Copy link
Contributor

Choose a reason for hiding this comment

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

Done

.count()
.execute_async(&conn)
.get_result_async(&conn)
Copy link
Contributor

Choose a reason for hiding this comment

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

same deal here

let in_use = diesel::dsl::select(diesel::dsl::exists(
  bgp_config_dsl::bgp_config
    .filter(bgp_config::bgp_announce_set_id.eq(id))
    .filter(bgp_config::time_deleted.is_null())
))
.get_result_async::<bool>(&conn)
.await?;

Copy link
Contributor

Choose a reason for hiding this comment

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

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants