@@ -105,10 +105,12 @@ fn skippable_version(
105
105
/// Reasons why [DataStore::ensure_schema] might fail
106
106
#[ derive( thiserror:: Error , Debug ) ]
107
107
pub enum EnsureSchemaError {
108
- /// This Nexus is too old to understand the schema
108
+ /// This Nexus is too old to use the schema currently in the database,
109
+ /// or quiescing has started (meaning that the schema will be updating
110
+ /// beyond this Nexus' compatibility very soon).
109
111
///
110
- /// This may happen when an old Nexus is booting / rebooting during
111
- /// a handoff to a newer Nexus.
112
+ /// Typically, this happens during an upgrade when the older version of
113
+ /// Nexus is starting up during the handoff to the newer Nexus.
112
114
#[ error( "Nexus is too old to use this schema; handoff: {handoff}" ) ]
113
115
NexusTooOld {
114
116
/// Should this Nexus still try to participate in handoff to a newer
@@ -141,8 +143,9 @@ pub enum EnsureSchemaError {
141
143
Other ( #[ from] anyhow:: Error ) ,
142
144
}
143
145
144
- /// Describes whether or not [DataStore::ensure_schema] will proceed
145
- /// with an update.
146
+ /// Describes whether or not [DataStore::ensure_schema] should proceed
147
+ /// with a schema update if it finds the currently-deployed schema is
148
+ /// out-of-date.
146
149
pub enum UpdateConfiguration < ' a > {
147
150
/// The update will not be triggered
148
151
Disabled ,
@@ -152,12 +155,12 @@ pub enum UpdateConfiguration<'a> {
152
155
/// Known schema versions, and ways to upgrade between them
153
156
all_versions : & ' a AllSchemaVersions ,
154
157
155
- /// If "true", ignore the quiesce status in the database
158
+ /// If "true", proceed with schema updates (if necessary) even when the
159
+ /// database state suggests older Nexus instances may have not quiesced.
156
160
///
157
- /// This can be used to ignore the work of ongoing Nexuses which may be
158
- /// shutting down, and should only be set to "true" cautiously (e.g.,
159
- /// this is used by the schema-updater binary, which can be used by
160
- /// operators).
161
+ /// This should only be set to "true" cautiously (e.g., this is used by
162
+ /// the schema-updater binary, which can be used by operators when they
163
+ /// know old Nexus instances are not running).
161
164
///
162
165
/// For most cases, this should be set to "false".
163
166
ignore_quiesce : bool ,
@@ -483,6 +486,9 @@ impl DataStore {
483
486
. await
484
487
. map_err ( |e| public_error_from_diesel ( e, ErrorHandler :: Server ) ) ?;
485
488
if base. version ( ) . 0 < nexus_db_model:: QUIESCE_VERSION {
489
+ // TODO(https://github.com/oxidecomputer/omicron/issues/8751):
490
+ // Remove this backwards compatibility layer.
491
+ //
486
492
// Why are we treating this case as "quiesced = true"?
487
493
//
488
494
// - If Nexus wants to be running on a schema older than
@@ -797,7 +803,7 @@ mod test {
797
803
let quiesce_started = true ;
798
804
let quiesce_completed = true ;
799
805
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
800
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
806
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
801
807
802
808
let _ = futures:: future:: join_all ( ( 0 ..10 ) . map ( |_| {
803
809
let all_versions = all_versions. clone ( ) ;
@@ -936,7 +942,7 @@ mod test {
936
942
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
937
943
let quiesce_started = true ;
938
944
let quiesce_completed = true ;
939
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
945
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
940
946
while let Err ( e) = datastore
941
947
. ensure_schema (
942
948
& log,
@@ -973,24 +979,29 @@ mod test {
973
979
logctx. cleanup_successful ( ) ;
974
980
}
975
981
976
- async fn set_quisece (
982
+ async fn set_quiesce (
977
983
datastore : & DataStore ,
978
984
started : bool ,
979
985
completed : bool ,
980
986
) {
981
987
let conn = datastore. pool_connection_for_tests ( ) . await . unwrap ( ) ;
982
- diesel:: dsl:: sql :: < diesel:: sql_types:: Integer > ( & format ! (
983
- "UPDATE omicron.public.db_metadata \
984
- SET \
985
- quiesce_started = {started}, \
986
- quiesce_completed = {completed} \
987
- WHERE singleton = TRUE"
988
- ) )
989
- . execute_async ( & * conn)
990
- . await
991
- . expect ( "Failed to update metadata" ) ;
988
+
989
+ use nexus_db_schema:: schema:: db_metadata:: dsl;
990
+
991
+ diesel:: update ( dsl:: db_metadata)
992
+ . filter ( dsl:: singleton. eq ( true ) )
993
+ . set ( (
994
+ dsl:: quiesce_started. eq ( started) ,
995
+ dsl:: quiesce_completed. eq ( completed) ,
996
+ ) )
997
+ . execute_async ( & * conn)
998
+ . await
999
+ . expect ( "Failed to update metadata" ) ;
992
1000
}
993
1001
1002
+ // This test validates what happens when an old Nexus interacts with a
1003
+ // database that has already started (or completed) going through a
1004
+ // schema migration.
994
1005
#[ tokio:: test]
995
1006
async fn ensure_schema_with_old_nexus ( ) {
996
1007
let logctx = dev:: test_setup_log ( "ensure_schema_with_old_nexus" ) ;
@@ -999,16 +1010,16 @@ mod test {
999
1010
let pool = db. pool ( ) ;
1000
1011
1001
1012
// The contents don't really matter here - just make the schema appear
1002
- // "old" .
1013
+ // older than the current Nexus expects .
1003
1014
let mut old_schema = SCHEMA_VERSION ;
1004
1015
old_schema. major -= 1 ;
1005
1016
1006
- // Case: Version matches the DB, and quiesce has started.
1017
+ // Case: Nexus version matches the DB, and quiesce has started.
1007
1018
{
1008
1019
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1009
1020
let quiesce_started = true ;
1010
1021
let quiesce_completed = false ;
1011
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1022
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1012
1023
1013
1024
let Err ( err) = datastore
1014
1025
. ensure_schema (
@@ -1026,12 +1037,12 @@ mod test {
1026
1037
) ;
1027
1038
}
1028
1039
1029
- // Case: Version matches the DB, and quiesce has completed.
1040
+ // Case: Nexus version matches the DB, and quiesce has completed.
1030
1041
{
1031
1042
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1032
1043
let quiesce_started = true ;
1033
1044
let quiesce_completed = true ;
1034
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1045
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1035
1046
1036
1047
let Err ( err) = datastore
1037
1048
. ensure_schema (
@@ -1060,7 +1071,7 @@ mod test {
1060
1071
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1061
1072
let quiesce_started = false ;
1062
1073
let quiesce_completed = false ;
1063
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1074
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1064
1075
1065
1076
let Err ( err) = datastore
1066
1077
. ensure_schema ( & log, old_schema, UpdateConfiguration :: Disabled )
@@ -1110,7 +1121,7 @@ mod test {
1110
1121
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1111
1122
let quiesce_started = false ;
1112
1123
let quiesce_completed = false ;
1113
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1124
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1114
1125
1115
1126
let Err ( err) = datastore
1116
1127
. ensure_schema (
@@ -1134,7 +1145,7 @@ mod test {
1134
1145
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1135
1146
let quiesce_started = true ;
1136
1147
let quiesce_completed = false ;
1137
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1148
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1138
1149
1139
1150
let Err ( err) = datastore
1140
1151
. ensure_schema (
@@ -1159,7 +1170,7 @@ mod test {
1159
1170
// This should let us proceed with the update.
1160
1171
let quiesce_started = true ;
1161
1172
let quiesce_completed = true ;
1162
- set_quisece ( & datastore, quiesce_started, quiesce_completed) . await ;
1173
+ set_quiesce ( & datastore, quiesce_started, quiesce_completed) . await ;
1163
1174
datastore
1164
1175
. ensure_schema (
1165
1176
& log,
@@ -1203,7 +1214,7 @@ mod test {
1203
1214
let mut new_schema = SCHEMA_VERSION ;
1204
1215
new_schema. major += 1 ;
1205
1216
1206
- // Load the new version, but don't enabled update.
1217
+ // Load the new version, but don't enable update.
1207
1218
let datastore = DataStore :: new_unchecked ( log. clone ( ) , pool. clone ( ) ) ;
1208
1219
let Err ( err) = datastore
1209
1220
. ensure_schema ( & log, new_schema, UpdateConfiguration :: Disabled )
0 commit comments